File: remote_resolver.go

package info (click to toggle)
glab 1.53.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 20,936 kB
  • sloc: sh: 295; makefile: 153; perl: 99; ruby: 68; javascript: 67
file content (99 lines) | stat: -rw-r--r-- 2,733 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package cmdutils

import (
	"errors"
	"net/url"
	"sort"
	"strings"

	"gitlab.com/gitlab-org/cli/internal/config"
	"gitlab.com/gitlab-org/cli/internal/glrepo"
	"gitlab.com/gitlab-org/cli/pkg/git"
	"gitlab.com/gitlab-org/cli/pkg/glinstance"
)

type remoteResolver struct {
	readRemotes   func() (git.RemoteSet, error)
	getConfig     func() (config.Config, error)
	urlTranslator func(*url.URL) *url.URL
}

func (rr *remoteResolver) Resolver(hostOverride string) func() (glrepo.Remotes, error) {
	var cachedRemotes glrepo.Remotes
	var remotesError error

	return func() (glrepo.Remotes, error) {
		if cachedRemotes != nil || remotesError != nil {
			return cachedRemotes, remotesError
		}

		gitRemotes, err := rr.readRemotes()
		if err != nil {
			remotesError = err
			return nil, err
		}
		if len(gitRemotes) == 0 {
			remotesError = errors.New("no git remotes found")
			return nil, remotesError
		}

		sshTranslate := rr.urlTranslator
		if sshTranslate == nil {
			sshTranslate = git.ParseSSHConfig().Translator()
		}
		resolvedRemotes := glrepo.TranslateRemotes(gitRemotes, sshTranslate)

		cfg, err := rr.getConfig()
		if err != nil {
			return nil, err
		}

		knownHosts := map[string]bool{}
		knownHosts[glinstance.Default()] = true
		if authenticatedHosts, err := cfg.Hosts(); err == nil {
			for _, h := range authenticatedHosts {
				knownHosts[h] = true
			}
		}

		// filter remotes to only those sharing a single, known hostname
		var hostname string
		cachedRemotes = glrepo.Remotes{}
		sort.Sort(resolvedRemotes)

		if hostOverride != "" {
			for _, r := range resolvedRemotes {
				if strings.EqualFold(r.RepoHost(), hostOverride) {
					cachedRemotes = append(cachedRemotes, r)
				}
			}

			if len(cachedRemotes) == 0 {
				remotesError = errors.New("none of the git remotes configured for this repository correspond to the GITLAB_HOST environment variable. Try adding a matching remote or unsetting the variable.\n\n" +
					"GITLAB_HOST is currently set to " + hostOverride + "\n\nConfigured remotes: " + resolvedRemotes.UniqueHosts())
				return nil, remotesError
			}

			return cachedRemotes, nil
		}

		for _, r := range resolvedRemotes {
			if hostname == "" {
				if !knownHosts[r.RepoHost()] {
					continue
				}
				hostname = r.RepoHost()
			} else if r.RepoHost() != hostname {
				continue
			}
			cachedRemotes = append(cachedRemotes, r)
		}

		if len(cachedRemotes) == 0 {
			remotesError = errors.New("none of the git remotes configured for this repository point to a known GitLab host. Please use `glab auth login` to authenticate and configure a new host for glab.\n\n" +
				"Configured remotes: " + resolvedRemotes.UniqueHosts())
			return nil, remotesError
		}
		return cachedRemotes, nil
	}
}