mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
Expose service info (provider, host, owner, repo) from the hosting service
The github pull-request fetcher needs to know whether a given remote is a
github-type service, which host its API lives on, and which owner/repo to
query against. Today the fetcher hardcodes the first two ("does the URL
contain github.com" and "https://api.github.com/graphql") and re-derives
owner/repo from the remote, which precludes GitHub Enterprise and makes
the fetch entry point take more arguments than it needs.
Add an accessor on the hosting service manager that exposes the already-
resolved service domain together with the parsed owner/repo, so callers
can answer all of these questions without reaching into the manager's
internals.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
88c540db12
commit
21d58085f4
|
|
@ -25,6 +25,10 @@ func (self *HostingService) GetRepoNameFromRemoteURL(remoteURL string) (string,
|
|||
return self.getHostingServiceMgr(remoteURL).GetRepoName()
|
||||
}
|
||||
|
||||
func (self *HostingService) GetServiceInfo(remoteURL string) (hosting_service.ServiceInfo, error) {
|
||||
return self.getHostingServiceMgr(remoteURL).GetServiceInfo()
|
||||
}
|
||||
|
||||
// getting this on every request rather than storing it in state in case our remoteURL changes
|
||||
// from one invocation to the next. Note however that we're currently caching config
|
||||
// results so we might want to invalidate the cache here if it becomes a problem.
|
||||
|
|
|
|||
|
|
@ -73,6 +73,42 @@ func (self *HostingServiceMgr) GetRepoName() (string, error) {
|
|||
return repoName, nil
|
||||
}
|
||||
|
||||
// ServiceInfo holds the resolved hosting service for a remote URL. Owner
|
||||
// comes from the "owner" named regex capture, which only exists for
|
||||
// owner/repo-shaped providers (github, gitlab, bitbucket, gitea, codeberg);
|
||||
// it's empty for azuredevops and bitbucketServer, whose URLs are organised
|
||||
// differently. Repository is populated for every provider, but RepoName may
|
||||
// have more than two segments (e.g. "org/project/repo" for azuredevops).
|
||||
type ServiceInfo struct {
|
||||
Provider string // e.g. "github"
|
||||
WebDomain string // e.g. "github.com", or "git.acme.com" for an on-prem instance
|
||||
Owner string // e.g. "jesseduffield"
|
||||
Repository string // e.g. "lazygit"
|
||||
RepoName string // e.g. "jesseduffield/lazygit"
|
||||
}
|
||||
|
||||
// GetServiceInfo identifies which hosting service the configured remote URL
|
||||
// belongs to and returns enough information to talk to its web/API host.
|
||||
func (self *HostingServiceMgr) GetServiceInfo() (ServiceInfo, error) {
|
||||
serviceDomain, err := self.getServiceDomain(self.remoteURL)
|
||||
if err != nil {
|
||||
return ServiceInfo{}, err
|
||||
}
|
||||
|
||||
matches, err := serviceDomain.serviceDefinition.parseRemoteUrl(self.remoteURL)
|
||||
if err != nil {
|
||||
return ServiceInfo{}, err
|
||||
}
|
||||
|
||||
return ServiceInfo{
|
||||
Provider: serviceDomain.serviceDefinition.provider,
|
||||
WebDomain: serviceDomain.webDomain,
|
||||
Owner: matches["owner"],
|
||||
Repository: matches["repo"],
|
||||
RepoName: utils.ResolvePlaceholderString(serviceDomain.serviceDefinition.repoNameTemplate, matches),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (self *HostingServiceMgr) getService() (*Service, error) {
|
||||
serviceDomain, err := self.getServiceDomain(self.remoteURL)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -577,3 +577,107 @@ func TestGetPullRequestURL(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServiceInfo(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
name string
|
||||
remoteURL string
|
||||
configServiceDomains map[string]string
|
||||
expected ServiceInfo
|
||||
}{
|
||||
{
|
||||
name: "github.com SSH",
|
||||
remoteURL: "git@github.com:jesseduffield/lazygit.git",
|
||||
expected: ServiceInfo{
|
||||
Provider: "github",
|
||||
WebDomain: "github.com",
|
||||
Owner: "jesseduffield",
|
||||
Repository: "lazygit",
|
||||
RepoName: "jesseduffield/lazygit",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "github enterprise with same git and web host",
|
||||
remoteURL: "git@github.example.com:my-org/my-repo.git",
|
||||
configServiceDomains: map[string]string{
|
||||
"github.example.com": "github:github.example.com",
|
||||
},
|
||||
expected: ServiceInfo{
|
||||
Provider: "github",
|
||||
WebDomain: "github.example.com",
|
||||
Owner: "my-org",
|
||||
Repository: "my-repo",
|
||||
RepoName: "my-org/my-repo",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "github enterprise with distinct git and web hosts",
|
||||
remoteURL: "git@git.example.com:my-org/my-repo.git",
|
||||
configServiceDomains: map[string]string{
|
||||
"git.example.com": "github:ghe.example.com",
|
||||
},
|
||||
expected: ServiceInfo{
|
||||
Provider: "github",
|
||||
WebDomain: "ghe.example.com",
|
||||
Owner: "my-org",
|
||||
Repository: "my-repo",
|
||||
RepoName: "my-org/my-repo",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "github enterprise with web host port",
|
||||
remoteURL: "git@git.example.com:my-org/my-repo.git",
|
||||
configServiceDomains: map[string]string{
|
||||
"git.example.com": "github:ghe.example.com:8443",
|
||||
},
|
||||
expected: ServiceInfo{
|
||||
Provider: "github",
|
||||
WebDomain: "ghe.example.com:8443",
|
||||
Owner: "my-org",
|
||||
Repository: "my-repo",
|
||||
RepoName: "my-org/my-repo",
|
||||
},
|
||||
},
|
||||
{
|
||||
// azuredevops uses org/project/repo named captures rather than
|
||||
// owner/repo, so Owner is unpopulated and RepoName has three
|
||||
// segments rather than the usual two.
|
||||
name: "azuredevops",
|
||||
remoteURL: "https://myorg@dev.azure.com/myorg/myproject/_git/myrepo",
|
||||
expected: ServiceInfo{
|
||||
Provider: "azuredevops",
|
||||
WebDomain: "dev.azure.com",
|
||||
Repository: "myrepo",
|
||||
RepoName: "myorg/myproject/myrepo",
|
||||
},
|
||||
},
|
||||
{
|
||||
// bitbucketServer uses project/repo named captures, so Owner is
|
||||
// unpopulated and RepoName is project/repo rather than owner/repo.
|
||||
name: "bitbucketServer",
|
||||
remoteURL: "https://mycompany.bitbucket.com/scm/myproject/myrepo.git",
|
||||
configServiceDomains: map[string]string{
|
||||
"mycompany.bitbucket.com": "bitbucketServer:mycompany.bitbucket.com",
|
||||
},
|
||||
expected: ServiceInfo{
|
||||
Provider: "bitbucketServer",
|
||||
WebDomain: "mycompany.bitbucket.com",
|
||||
Repository: "myrepo",
|
||||
RepoName: "myproject/myrepo",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.name, func(t *testing.T) {
|
||||
tr := i18n.EnglishTranslationSet()
|
||||
log := &fakes.FakeFieldLogger{}
|
||||
mgr := NewHostingServiceMgr(log, tr, s.remoteURL, s.configServiceDomains)
|
||||
|
||||
info, err := mgr.GetServiceInfo()
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, s.expected, info)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue