diff --git a/pkg/commands/hosting_service/definitions.go b/pkg/commands/hosting_service/definitions.go index 25e449340..130bf0481 100644 --- a/pkg/commands/hosting_service/definitions.go +++ b/pkg/commands/hosting_service/definitions.go @@ -6,7 +6,11 @@ var defaultUrlRegexStrings = []string{ `^(?:https?|ssh)://[^/]+/(?P.*)/(?P.*?)(?:\.git)?$`, `^(.*?@)?.*:/*(?P.*)/(?P.*?)(?:\.git)?$`, } -var defaultRepoURLTemplate = "https://{{.webDomain}}/{{.owner}}/{{.repo}}" + +var ( + defaultRepoURLTemplate = "https://{{.webDomain}}/{{.owner}}/{{.repo}}" + defaultRepoNameTemplate = "{{.owner}}/{{.repo}}" +) // we've got less type safety using go templates but this lends itself better to // users adding custom service definitions in their config @@ -17,6 +21,7 @@ var githubServiceDef = ServiceDefinition{ commitURL: "/commit/{{.CommitHash}}", regexStrings: defaultUrlRegexStrings, repoURLTemplate: defaultRepoURLTemplate, + repoNameTemplate: defaultRepoNameTemplate, } var bitbucketServiceDef = ServiceDefinition{ @@ -28,7 +33,8 @@ var bitbucketServiceDef = ServiceDefinition{ `^(?:https?|ssh)://.*/(?P.*)/(?P.*?)(?:\.git)?$`, `^.*@.*:/*(?P.*)/(?P.*?)(?:\.git)?$`, }, - repoURLTemplate: defaultRepoURLTemplate, + repoURLTemplate: defaultRepoURLTemplate, + repoNameTemplate: defaultRepoNameTemplate, } var gitLabServiceDef = ServiceDefinition{ @@ -38,6 +44,7 @@ var gitLabServiceDef = ServiceDefinition{ commitURL: "/-/commit/{{.CommitHash}}", regexStrings: defaultUrlRegexStrings, repoURLTemplate: defaultRepoURLTemplate, + repoNameTemplate: defaultRepoNameTemplate, } var azdoServiceDef = ServiceDefinition{ @@ -51,7 +58,8 @@ var azdoServiceDef = ServiceDefinition{ `^https://.*@dev.azure.com/(?P.*?)/(?P.*?)/_git/(?P.*?)(?:\.git)?$`, `^https://.*/(?P.*?)/(?P.*?)/_git/(?P.*?)(?:\.git)?$`, }, - repoURLTemplate: "https://{{.webDomain}}/{{.org}}/{{.project}}/_git/{{.repo}}", + repoURLTemplate: "https://{{.webDomain}}/{{.org}}/{{.project}}/_git/{{.repo}}", + repoNameTemplate: "{{.org}}/{{.project}}/{{.repo}}", } var bitbucketServerServiceDef = ServiceDefinition{ @@ -63,7 +71,8 @@ var bitbucketServerServiceDef = ServiceDefinition{ `^ssh://git@.*/(?P.*)/(?P.*?)(?:\.git)?$`, `^https://.*/scm/(?P.*)/(?P.*?)(?:\.git)?$`, }, - repoURLTemplate: "https://{{.webDomain}}/projects/{{.project}}/repos/{{.repo}}", + repoURLTemplate: "https://{{.webDomain}}/projects/{{.project}}/repos/{{.repo}}", + repoNameTemplate: "{{.project}}/{{.repo}}", } var giteaServiceDef = ServiceDefinition{ diff --git a/pkg/commands/hosting_service/hosting_service.go b/pkg/commands/hosting_service/hosting_service.go index 1c328fd0d..620d0d0a7 100644 --- a/pkg/commands/hosting_service/hosting_service.go +++ b/pkg/commands/hosting_service/hosting_service.go @@ -61,6 +61,18 @@ func (self *HostingServiceMgr) GetCommitURL(commitHash string) (string, error) { return pullRequestURL, nil } +// e.g. 'jesseduffield/lazygit' +func (self *HostingServiceMgr) GetRepoName() (string, error) { + gitService, err := self.getService() + if err != nil { + return "", err + } + + repoName := gitService.repoName + + return repoName, nil +} + func (self *HostingServiceMgr) getService() (*Service, error) { serviceDomain, err := self.getServiceDomain(self.remoteURL) if err != nil { @@ -72,8 +84,14 @@ func (self *HostingServiceMgr) getService() (*Service, error) { return nil, err } + repoName, err := serviceDomain.serviceDefinition.getRepoNameFromRemoteURL(self.remoteURL) + if err != nil { + return nil, err + } + return &Service{ repoURL: repoURL, + repoName: repoName, ServiceDefinition: serviceDomain.serviceDefinition, }, nil } @@ -144,24 +162,68 @@ type ServiceDefinition struct { regexStrings []string // can expect 'webdomain' to be passed in. Otherwise, you get to pick what we match in the regex - repoURLTemplate string + repoURLTemplate string + repoNameTemplate string } func (self ServiceDefinition) getRepoURLFromRemoteURL(url string, webDomain string) (string, error) { + matches, err := self.parseRemoteUrl(url) + if err != nil { + return "", err + } + + matches["webDomain"] = webDomain + return utils.ResolvePlaceholderString(self.repoURLTemplate, matches), nil +} + +func (self ServiceDefinition) getRepoNameFromRemoteURL(url string) (string, error) { + matches, err := self.parseRemoteUrl(url) + if err != nil { + return "", err + } + + return utils.ResolvePlaceholderString(self.repoNameTemplate, matches), nil +} + +func (self ServiceDefinition) parseRemoteUrl(url string) (map[string]string, error) { for _, regexStr := range self.regexStrings { re := regexp.MustCompile(regexStr) - input := utils.FindNamedMatches(re, url) - if input != nil { - input["webDomain"] = webDomain - return utils.ResolvePlaceholderString(self.repoURLTemplate, input), nil + matches := utils.FindNamedMatches(re, url) + if matches != nil { + return matches, nil } } - return "", errors.New("Failed to parse repo information from url") + return nil, errors.New("Failed to parse repo information from url") +} + +// RepoInformation holds the owner and repository name parsed from a remote URL. +type RepoInformation struct { + Owner string + Repository string +} + +// GetRepoInfoFromURL parses a remote URL (SSH or HTTPS) and extracts the +// owner and repository name using the default URL regex patterns. +func GetRepoInfoFromURL(url string) (RepoInformation, error) { + for _, regexStr := range defaultUrlRegexStrings { + re := regexp.MustCompile(regexStr) + matches := utils.FindNamedMatches(re, url) + if matches != nil { + return RepoInformation{ + Owner: matches["owner"], + Repository: matches["repo"], + }, nil + } + } + + return RepoInformation{}, errors.New("Failed to parse repo information from url") } type Service struct { repoURL string + // e.g. 'jesseduffield/lazygit' + repoName string ServiceDefinition }