mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-11 12:25:47 +02:00
refactor
This commit is contained in:
parent
ac8e76bee0
commit
79a72fe7a6
17 changed files with 294 additions and 211 deletions
|
@ -124,17 +124,15 @@ func NewApp(config config.AppConfigurer, common *common.Common) (*App, error) {
|
|||
|
||||
func (app *App) validateGhVersion() error {
|
||||
output, err := app.OSCommand.Cmd.New("gh --version").RunWithOutput()
|
||||
// if we get an error anywhere here we'll show the same status
|
||||
minVersionError := errors.New(app.Tr.MinGhVersionError)
|
||||
if err != nil {
|
||||
return minVersionError
|
||||
return fmt.Errorf(app.Tr.FailedToObtainGhVersionError, err.Error())
|
||||
}
|
||||
|
||||
if isGhVersionValid(output) {
|
||||
return nil
|
||||
if !isGhVersionValid(output) {
|
||||
return errors.New(app.Tr.MinGhVersionError)
|
||||
}
|
||||
|
||||
return minVersionError
|
||||
return nil
|
||||
}
|
||||
|
||||
func isGhVersionValid(versionStr string) bool {
|
||||
|
@ -162,17 +160,15 @@ func isGhVersionValid(versionStr string) bool {
|
|||
|
||||
func (app *App) validateGitVersion() error {
|
||||
output, err := app.OSCommand.Cmd.New("git --version").RunWithOutput()
|
||||
// if we get an error anywhere here we'll show the same status
|
||||
minVersionError := errors.New(app.Tr.MinGitVersionError)
|
||||
if err != nil {
|
||||
return minVersionError
|
||||
return fmt.Errorf(app.Tr.FailedToObtainGitVersionError, err.Error())
|
||||
}
|
||||
|
||||
if isGitVersionValid(output) {
|
||||
return nil
|
||||
if !isGitVersionValid(output) {
|
||||
return errors.New(app.Tr.MinGitVersionError)
|
||||
}
|
||||
|
||||
return minVersionError
|
||||
return nil
|
||||
}
|
||||
|
||||
func isGitVersionValid(versionStr string) bool {
|
||||
|
|
|
@ -22,23 +22,24 @@ import (
|
|||
|
||||
// GitCommand is our main git interface
|
||||
type GitCommand struct {
|
||||
Branch *git_commands.BranchCommands
|
||||
Commit *git_commands.CommitCommands
|
||||
Config *git_commands.ConfigCommands
|
||||
Custom *git_commands.CustomCommands
|
||||
File *git_commands.FileCommands
|
||||
Flow *git_commands.FlowCommands
|
||||
Patch *git_commands.PatchCommands
|
||||
Rebase *git_commands.RebaseCommands
|
||||
Remote *git_commands.RemoteCommands
|
||||
Stash *git_commands.StashCommands
|
||||
Status *git_commands.StatusCommands
|
||||
Submodule *git_commands.SubmoduleCommands
|
||||
Sync *git_commands.SyncCommands
|
||||
Tag *git_commands.TagCommands
|
||||
WorkingTree *git_commands.WorkingTreeCommands
|
||||
Bisect *git_commands.BisectCommands
|
||||
Gh *git_commands.GhCommands
|
||||
Branch *git_commands.BranchCommands
|
||||
Commit *git_commands.CommitCommands
|
||||
Config *git_commands.ConfigCommands
|
||||
Custom *git_commands.CustomCommands
|
||||
File *git_commands.FileCommands
|
||||
Flow *git_commands.FlowCommands
|
||||
Patch *git_commands.PatchCommands
|
||||
Rebase *git_commands.RebaseCommands
|
||||
Remote *git_commands.RemoteCommands
|
||||
Stash *git_commands.StashCommands
|
||||
Status *git_commands.StatusCommands
|
||||
Submodule *git_commands.SubmoduleCommands
|
||||
Sync *git_commands.SyncCommands
|
||||
Tag *git_commands.TagCommands
|
||||
WorkingTree *git_commands.WorkingTreeCommands
|
||||
Bisect *git_commands.BisectCommands
|
||||
Gh *git_commands.GhCommands
|
||||
HostingService *git_commands.HostingService
|
||||
|
||||
Loaders Loaders
|
||||
}
|
||||
|
@ -121,25 +122,27 @@ func NewGitCommandAux(
|
|||
patchCommands := git_commands.NewPatchCommands(gitCommon, rebaseCommands, commitCommands, statusCommands, stashCommands, patchManager)
|
||||
bisectCommands := git_commands.NewBisectCommands(gitCommon)
|
||||
ghCommands := git_commands.NewGhCommand(gitCommon)
|
||||
hostingServiceCommands := git_commands.NewHostingServiceCommand(gitCommon)
|
||||
|
||||
return &GitCommand{
|
||||
Branch: branchCommands,
|
||||
Commit: commitCommands,
|
||||
Config: configCommands,
|
||||
Custom: customCommands,
|
||||
File: fileCommands,
|
||||
Flow: flowCommands,
|
||||
Patch: patchCommands,
|
||||
Rebase: rebaseCommands,
|
||||
Remote: remoteCommands,
|
||||
Stash: stashCommands,
|
||||
Status: statusCommands,
|
||||
Submodule: submoduleCommands,
|
||||
Sync: syncCommands,
|
||||
Tag: tagCommands,
|
||||
Bisect: bisectCommands,
|
||||
WorkingTree: workingTreeCommands,
|
||||
Gh: ghCommands,
|
||||
Branch: branchCommands,
|
||||
Commit: commitCommands,
|
||||
Config: configCommands,
|
||||
Custom: customCommands,
|
||||
File: fileCommands,
|
||||
Flow: flowCommands,
|
||||
Patch: patchCommands,
|
||||
Rebase: rebaseCommands,
|
||||
Remote: remoteCommands,
|
||||
Stash: stashCommands,
|
||||
Status: statusCommands,
|
||||
Submodule: submoduleCommands,
|
||||
Sync: syncCommands,
|
||||
Tag: tagCommands,
|
||||
Bisect: bisectCommands,
|
||||
WorkingTree: workingTreeCommands,
|
||||
Gh: ghCommands,
|
||||
HostingService: hostingServiceCommands,
|
||||
Loaders: Loaders{
|
||||
Branches: loaders.NewBranchLoader(cmn, branchCommands.GetRawBranches, branchCommands.CurrentBranchName, configCommands),
|
||||
CommitFiles: loaders.NewCommitFileLoader(cmn, cmd),
|
||||
|
|
|
@ -25,11 +25,15 @@ func (self *GhCommands) BaseRepo() error {
|
|||
|
||||
// Ex: git config --local --add "remote.origin.gh-resolved" "jesseduffield/lazygit"
|
||||
func (self *GhCommands) SetBaseRepo(repository string) (string, error) {
|
||||
return self.cmd.New(fmt.Sprintf("git config --local --add \"remote.origin.gh-resolved\" \"%s\"", repository)).RunWithOutput()
|
||||
return self.cmd.New(
|
||||
fmt.Sprintf("git config --local --add \"remote.origin.gh-resolved\" \"%s\"", repository),
|
||||
).RunWithOutput()
|
||||
}
|
||||
|
||||
func (self *GhCommands) prList() (string, error) {
|
||||
return self.cmd.New("gh pr list --limit 500 --state all --json state,url,number,headRefName,headRepositoryOwner").RunWithOutput()
|
||||
return self.cmd.New(
|
||||
"gh pr list --limit 500 --state all --json state,url,number,headRefName,headRepositoryOwner",
|
||||
).RunWithOutput()
|
||||
}
|
||||
|
||||
func (self *GhCommands) GithubMostRecentPRs() ([]*models.GithubPullRequest, error) {
|
||||
|
@ -60,23 +64,33 @@ func GenerateGithubPullRequestMap(prs []*models.GithubPullRequest, branches []*m
|
|||
return res
|
||||
}
|
||||
|
||||
prWithStringKey := map[string]models.GithubPullRequest{}
|
||||
// A PR can be identified by two things: the owner e.g. 'jesseduffield' and the
|
||||
// branch name e.g. 'feature/my-feature'. The owner might be different
|
||||
// to the owner of the repo if the PR is from a fork of that repo.
|
||||
type prKey struct {
|
||||
owner string
|
||||
branchName string
|
||||
}
|
||||
|
||||
prByKey := map[prKey]models.GithubPullRequest{}
|
||||
|
||||
for _, pr := range prs {
|
||||
prWithStringKey[pr.UserName()+":"+pr.BranchName()] = *pr
|
||||
prByKey[prKey{owner: pr.UserName(), branchName: pr.BranchName()}] = *pr
|
||||
}
|
||||
|
||||
for _, branch := range branches {
|
||||
if !branch.IsTrackingRemote() || branch.UpstreamBranch == "" {
|
||||
if !branch.IsTrackingRemote() {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: support branches whose UpstreamRemote contains a full git
|
||||
// URL rather than just a remote name.
|
||||
owner, foundRemoteOwner := remotesToOwnersMap[branch.UpstreamRemote]
|
||||
if !foundRemoteOwner {
|
||||
continue
|
||||
}
|
||||
|
||||
pr, hasPr := prWithStringKey[owner+":"+branch.UpstreamBranch]
|
||||
pr, hasPr := prByKey[prKey{owner: owner, branchName: branch.UpstreamBranch}]
|
||||
|
||||
if !hasPr {
|
||||
continue
|
||||
|
@ -88,6 +102,24 @@ func GenerateGithubPullRequestMap(prs []*models.GithubPullRequest, branches []*m
|
|||
return res
|
||||
}
|
||||
|
||||
func getRemotesToOwnersMap(remotes []*models.Remote) map[string]string {
|
||||
res := map[string]string{}
|
||||
for _, remote := range remotes {
|
||||
if len(remote.Urls) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
res[remote.Name] = GetRepoInfoFromURL(remote.Urls[0]).Owner
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
type RepoInformation struct {
|
||||
Owner string
|
||||
Repository string
|
||||
}
|
||||
|
||||
// TODO: move this into hosting_service.go
|
||||
func GetRepoInfoFromURL(url string) RepoInformation {
|
||||
isHTTP := strings.HasPrefix(url, "http")
|
||||
|
||||
|
@ -112,20 +144,3 @@ func GetRepoInfoFromURL(url string) RepoInformation {
|
|||
Repository: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func getRemotesToOwnersMap(remotes []*models.Remote) map[string]string {
|
||||
res := map[string]string{}
|
||||
for _, remote := range remotes {
|
||||
if len(remote.Urls) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
res[remote.Name] = GetRepoInfoFromURL(remote.Urls[0]).Owner
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
type RepoInformation struct {
|
||||
Owner string
|
||||
Repository string
|
||||
}
|
||||
|
|
34
pkg/commands/git_commands/hosting_service.go
Normal file
34
pkg/commands/git_commands/hosting_service.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package git_commands
|
||||
|
||||
import "github.com/jesseduffield/lazygit/pkg/commands/hosting_service"
|
||||
|
||||
// a hosting service is something like github, gitlab, bitbucket etc
|
||||
type HostingService struct {
|
||||
*GitCommon
|
||||
}
|
||||
|
||||
func NewHostingServiceCommand(gitCommon *GitCommon) *HostingService {
|
||||
return &HostingService{
|
||||
GitCommon: gitCommon,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *HostingService) GetPullRequestURL(from string, to string) (string, error) {
|
||||
return self.getHostingServiceMgr(self.config.GetRemoteURL()).GetPullRequestURL(from, to)
|
||||
}
|
||||
|
||||
func (self *HostingService) GetCommitURL(commitSha string) (string, error) {
|
||||
return self.getHostingServiceMgr(self.config.GetRemoteURL()).GetCommitURL(commitSha)
|
||||
}
|
||||
|
||||
func (self *HostingService) GetRepoNameFromRemoteURL(remoteURL string) (string, error) {
|
||||
return self.getHostingServiceMgr(remoteURL).GetRepoName()
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (self *HostingService) getHostingServiceMgr(remoteURL string) *hosting_service.HostingServiceMgr {
|
||||
configServices := self.UserConfig.Services
|
||||
return hosting_service.NewHostingServiceMgr(self.Log, self.Tr, remoteURL, configServices)
|
||||
}
|
|
@ -6,7 +6,11 @@ var defaultUrlRegexStrings = []string{
|
|||
`^(?:https?|ssh)://[^/]+/(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
||||
`^git@.*:(?P<owner>.*)/(?P<repo>.*?)(?:\.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/{{.CommitSha}}",
|
||||
regexStrings: defaultUrlRegexStrings,
|
||||
repoURLTemplate: defaultRepoURLTemplate,
|
||||
repoNameTemplate: defaultRepoNameTemplate,
|
||||
}
|
||||
|
||||
var bitbucketServiceDef = ServiceDefinition{
|
||||
|
@ -28,7 +33,8 @@ var bitbucketServiceDef = ServiceDefinition{
|
|||
`^(?:https?|ssh)://.*/(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
||||
`^.*@.*:(?P<owner>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
||||
},
|
||||
repoURLTemplate: defaultRepoURLTemplate,
|
||||
repoURLTemplate: defaultRepoURLTemplate,
|
||||
repoNameTemplate: defaultRepoNameTemplate,
|
||||
}
|
||||
|
||||
var gitLabServiceDef = ServiceDefinition{
|
||||
|
@ -38,6 +44,7 @@ var gitLabServiceDef = ServiceDefinition{
|
|||
commitURL: "/commit/{{.CommitSha}}",
|
||||
regexStrings: defaultUrlRegexStrings,
|
||||
repoURLTemplate: defaultRepoURLTemplate,
|
||||
repoNameTemplate: defaultRepoNameTemplate,
|
||||
}
|
||||
|
||||
var azdoServiceDef = ServiceDefinition{
|
||||
|
@ -50,6 +57,8 @@ var azdoServiceDef = ServiceDefinition{
|
|||
`^https://.*@dev.azure.com/(?P<org>.*?)/(?P<project>.*?)/_git/(?P<repo>.*?)(?:\.git)?$`,
|
||||
},
|
||||
repoURLTemplate: "https://{{.webDomain}}/{{.org}}/{{.project}}/_git/{{.repo}}",
|
||||
// TODO: verify this is actually correct
|
||||
repoNameTemplate: "{{.org}}/{{.project}}/{{.repo}}",
|
||||
}
|
||||
|
||||
var bitbucketServerServiceDef = ServiceDefinition{
|
||||
|
@ -62,6 +71,8 @@ var bitbucketServerServiceDef = ServiceDefinition{
|
|||
`^https://.*/scm/(?P<project>.*)/(?P<repo>.*?)(?:\.git)?$`,
|
||||
},
|
||||
repoURLTemplate: "https://{{.webDomain}}/projects/{{.project}}/repos/{{.repo}}",
|
||||
// TODO: verify this is actually correct
|
||||
repoNameTemplate: "{{.project}}/{{.repo}}",
|
||||
}
|
||||
|
||||
var serviceDefinitions = []ServiceDefinition{
|
||||
|
|
|
@ -61,6 +61,18 @@ func (self *HostingServiceMgr) GetCommitURL(commitSha 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
|
||||
}
|
||||
|
@ -147,24 +165,45 @@ 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")
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
repoURL string
|
||||
// e.g. 'jesseduffield/lazygit'
|
||||
repoName string
|
||||
ServiceDefinition
|
||||
}
|
||||
|
||||
|
|
|
@ -9,10 +9,12 @@ type GithubPullRequest struct {
|
|||
}
|
||||
|
||||
func (pr *GithubPullRequest) UserName() string {
|
||||
// e.g. 'jesseduffield'
|
||||
return pr.HeadRepositoryOwner.Login
|
||||
}
|
||||
|
||||
func (pr *GithubPullRequest) BranchName() string {
|
||||
// e.g. 'feature/my-feature'
|
||||
return pr.HeadRefName
|
||||
}
|
||||
|
||||
|
|
|
@ -23,55 +23,3 @@ func (gui *Gui) branchesRenderToMain() error {
|
|||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (gui *Gui) refreshGithubPullRequests() error {
|
||||
if err := gui.git.Gh.BaseRepo(); err == nil {
|
||||
err := gui.setGithubPullRequests()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gui.refreshBranches()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// when config not exits
|
||||
err := gui.refreshRemotes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_ = gui.c.Prompt(types.PromptOpts{
|
||||
Title: gui.c.Tr.SelectRemoteRepository,
|
||||
InitialContent: "",
|
||||
FindSuggestionsFunc: gui.helpers.Suggestions.GetRemoteRepoSuggestionsFunc(),
|
||||
HandleConfirm: func(repository string) error {
|
||||
return gui.c.WithWaitingStatus(gui.c.Tr.LcSelectingRemote, func() error {
|
||||
_, err := gui.git.Gh.SetBaseRepo(repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = gui.setGithubPullRequests()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gui.refreshBranches()
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) setGithubPullRequests() error {
|
||||
prs, err := gui.git.Gh.GithubMostRecentPRs()
|
||||
if err != nil {
|
||||
return gui.c.Error(err)
|
||||
}
|
||||
|
||||
gui.State.Model.PullRequests = prs
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -23,10 +23,9 @@ func (gui *Gui) resetControllers() {
|
|||
)
|
||||
|
||||
rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon, gui.State.Contexts, gui.git, refsHelper)
|
||||
suggestionsHelper := helpers.NewSuggestionsHelper(helperCommon, model, gui.refreshSuggestions)
|
||||
suggestionsHelper := helpers.NewSuggestionsHelper(helperCommon, gui.git, model, gui.refreshSuggestions)
|
||||
gui.helpers = &helpers.Helpers{
|
||||
Refs: refsHelper,
|
||||
Host: helpers.NewHostHelper(helperCommon, gui.git),
|
||||
PatchBuilding: helpers.NewPatchBuildingHelper(helperCommon, gui.git, gui.State.Contexts),
|
||||
Bisect: helpers.NewBisectHelper(helperCommon, gui.git),
|
||||
Suggestions: suggestionsHelper,
|
||||
|
|
|
@ -150,7 +150,7 @@ func (self *BasicCommitsController) copyCommitSHAToClipboard(commit *models.Comm
|
|||
}
|
||||
|
||||
func (self *BasicCommitsController) copyCommitURLToClipboard(commit *models.Commit) error {
|
||||
url, err := self.helpers.Host.GetCommitURL(commit.Sha)
|
||||
url, err := self.git.HostingService.GetCommitURL(commit.Sha)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ func (self *BasicCommitsController) copyCommitMessageToClipboard(commit *models.
|
|||
}
|
||||
|
||||
func (self *BasicCommitsController) openInBrowser(commit *models.Commit) error {
|
||||
url, err := self.helpers.Host.GetCommitURL(commit.Sha)
|
||||
url, err := self.git.HostingService.GetCommitURL(commit.Sha)
|
||||
if err != nil {
|
||||
return self.c.Error(err)
|
||||
}
|
||||
|
|
|
@ -195,7 +195,7 @@ func (self *BranchesController) copyPullRequestURL() error {
|
|||
return self.c.Error(errors.New(self.c.Tr.NoBranchOnRemote))
|
||||
}
|
||||
|
||||
url, err := self.helpers.Host.GetPullRequestURL(branch.Name, "")
|
||||
url, err := self.git.HostingService.GetPullRequestURL(branch.Name, "")
|
||||
if err != nil {
|
||||
return self.c.Error(err)
|
||||
}
|
||||
|
@ -462,7 +462,7 @@ func (self *BranchesController) createPullRequestMenu(selectedBranch *models.Bra
|
|||
}
|
||||
|
||||
func (self *BranchesController) createPullRequest(from string, to string) error {
|
||||
url, err := self.helpers.Host.GetPullRequestURL(from, to)
|
||||
url, err := self.git.HostingService.GetPullRequestURL(from, to)
|
||||
if err != nil {
|
||||
return self.c.Error(err)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ type Helpers struct {
|
|||
MergeAndRebase *MergeAndRebaseHelper
|
||||
MergeConflicts *MergeConflictsHelper
|
||||
CherryPick *CherryPickHelper
|
||||
Host *HostHelper
|
||||
PatchBuilding *PatchBuildingHelper
|
||||
GPG *GpgHelper
|
||||
Upstream *UpstreamHelper
|
||||
|
@ -27,7 +26,6 @@ func NewStubHelpers() *Helpers {
|
|||
MergeAndRebase: &MergeAndRebaseHelper{},
|
||||
MergeConflicts: &MergeConflictsHelper{},
|
||||
CherryPick: &CherryPickHelper{},
|
||||
Host: &HostHelper{},
|
||||
PatchBuilding: &PatchBuildingHelper{},
|
||||
GPG: &GpgHelper{},
|
||||
Upstream: &UpstreamHelper{},
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
package helpers
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/hosting_service"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
// this helper just wraps our hosting_service package
|
||||
|
||||
type IHostHelper interface {
|
||||
GetPullRequestURL(from string, to string) (string, error)
|
||||
GetCommitURL(commitSha string) (string, error)
|
||||
}
|
||||
|
||||
type HostHelper struct {
|
||||
c *types.HelperCommon
|
||||
git *commands.GitCommand
|
||||
}
|
||||
|
||||
func NewHostHelper(
|
||||
c *types.HelperCommon,
|
||||
git *commands.GitCommand,
|
||||
) *HostHelper {
|
||||
return &HostHelper{
|
||||
c: c,
|
||||
git: git,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *HostHelper) GetPullRequestURL(from string, to string) (string, error) {
|
||||
return self.getHostingServiceMgr().GetPullRequestURL(from, to)
|
||||
}
|
||||
|
||||
func (self *HostHelper) GetCommitURL(commitSha string) (string, error) {
|
||||
return self.getHostingServiceMgr().GetCommitURL(commitSha)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (self *HostHelper) getHostingServiceMgr() *hosting_service.HostingServiceMgr {
|
||||
remoteUrl := self.git.Config.GetRemoteURL()
|
||||
configServices := self.c.UserConfig.Services
|
||||
return hosting_service.NewHostingServiceMgr(self.c.Log, self.c.Tr, remoteUrl, configServices)
|
||||
}
|
|
@ -5,7 +5,7 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/jesseduffield/generics/slices"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
|
@ -37,6 +37,7 @@ type SuggestionsHelper struct {
|
|||
c *types.HelperCommon
|
||||
|
||||
model *types.Model
|
||||
git *commands.GitCommand
|
||||
refreshSuggestionsFn func()
|
||||
}
|
||||
|
||||
|
@ -44,11 +45,13 @@ var _ ISuggestionsHelper = &SuggestionsHelper{}
|
|||
|
||||
func NewSuggestionsHelper(
|
||||
c *types.HelperCommon,
|
||||
git *commands.GitCommand,
|
||||
model *types.Model,
|
||||
refreshSuggestionsFn func(),
|
||||
) *SuggestionsHelper {
|
||||
return &SuggestionsHelper{
|
||||
c: c,
|
||||
git: git,
|
||||
model: model,
|
||||
refreshSuggestionsFn: refreshSuggestionsFn,
|
||||
}
|
||||
|
@ -94,8 +97,12 @@ func (self *SuggestionsHelper) getRemoteRepoNames() []string {
|
|||
if len(remote.Urls) == 0 {
|
||||
continue
|
||||
}
|
||||
info := git_commands.GetRepoInfoFromURL(remote.Urls[0])
|
||||
result = append(result, fmt.Sprintf("%s/%s", info.Owner, info.Repository))
|
||||
repoName, err := self.git.HostingService.GetRepoNameFromRemoteURL(remote.Urls[0])
|
||||
if err != nil {
|
||||
self.c.Log.Error(err)
|
||||
continue
|
||||
}
|
||||
result = append(result, repoName)
|
||||
}
|
||||
|
||||
return result
|
||||
|
|
|
@ -134,15 +134,21 @@ func SetCustomBranches(customBranchColors map[string]string) {
|
|||
|
||||
func coloredPrNumber(pr *models.GithubPullRequest, hasPr bool) string {
|
||||
if hasPr {
|
||||
colour := style.FgMagenta // = state MERGED
|
||||
switch pr.State {
|
||||
case "OPEN":
|
||||
colour = style.FgGreen
|
||||
case "CLOSED":
|
||||
colour = style.FgRed
|
||||
}
|
||||
return colour.Sprint("#" + strconv.Itoa(pr.Number))
|
||||
return prColor(pr.State).Sprint("#" + strconv.Itoa(pr.Number))
|
||||
}
|
||||
|
||||
return ("")
|
||||
}
|
||||
|
||||
func prColor(state string) style.TextStyle {
|
||||
switch state {
|
||||
case "OPEN":
|
||||
return style.FgGreen
|
||||
case "CLOSED":
|
||||
return style.FgRed
|
||||
case "MERGED":
|
||||
return style.FgMagenta
|
||||
default:
|
||||
return style.FgDefault
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,21 +164,38 @@ func (gui *Gui) Refresh(options types.RefreshOptions) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// during startup, the bottleneck is fetching the reflog entries. We need these
|
||||
// on startup to sort the branches by recency. So we have two phases: INITIAL, and COMPLETE.
|
||||
// In the initial phase we don't get any reflog commits, but we asynchronously get them
|
||||
// and refresh the branches after that
|
||||
func (gui *Gui) refreshReflogCommitsConsideringStartup() {
|
||||
// during startup, the bottleneck is fetching the reflog entries and Github PRs, both of which affect the contents of the branches view.
|
||||
// So we have two phases: INITIAL, and COMPLETE.
|
||||
// In the initial phase we asynchronously refresh the dependencies (reflog entries and Github PRs) and then refresh the branches view.
|
||||
// After that, we synchronously refresh the dependencies
|
||||
func (gui *Gui) refreshBranchDependenciesConsideringStartup() {
|
||||
refreshDeps := func() {
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
go func() {
|
||||
_ = gui.refreshReflogCommits()
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
_ = gui.refreshGithubPullRequests()
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
switch gui.State.StartupStage {
|
||||
case INITIAL:
|
||||
go utils.Safe(func() {
|
||||
_ = gui.refreshReflogCommits()
|
||||
refreshDeps()
|
||||
gui.refreshBranches()
|
||||
gui.State.StartupStage = COMPLETE
|
||||
})
|
||||
|
||||
case COMPLETE:
|
||||
_ = gui.refreshReflogCommits()
|
||||
refreshDeps()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,7 +207,7 @@ func (gui *Gui) refreshCommits() {
|
|||
wg.Add(2)
|
||||
|
||||
go utils.Safe(func() {
|
||||
gui.refreshReflogCommitsConsideringStartup()
|
||||
gui.refreshBranchDependenciesConsideringStartup()
|
||||
|
||||
gui.refreshBranches()
|
||||
wg.Done()
|
||||
|
@ -237,14 +254,6 @@ func (gui *Gui) refreshCommitsWithLimit() error {
|
|||
}
|
||||
gui.State.Model.Commits = commits
|
||||
|
||||
if gui.Config.GetUserConfig().Git.EnableGhCommand {
|
||||
err = gui.refreshGithubPullRequests()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return gui.c.PostRefreshUpdate(gui.State.Contexts.LocalCommits)
|
||||
}
|
||||
|
||||
|
@ -719,3 +728,61 @@ func (gui *Gui) refreshMergePanel(isFocused bool) error {
|
|||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (gui *Gui) refreshGithubPullRequests() error {
|
||||
if !gui.Config.GetUserConfig().Git.EnableGhCommand {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := gui.git.Gh.BaseRepo(); err == nil {
|
||||
if err := gui.setGithubPullRequests(); err != nil {
|
||||
return gui.c.Error(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// when config not exists
|
||||
err := gui.refreshRemotes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_ = gui.c.Prompt(types.PromptOpts{
|
||||
Title: gui.c.Tr.SelectRemoteRepository,
|
||||
InitialContent: "",
|
||||
FindSuggestionsFunc: gui.helpers.Suggestions.GetRemoteRepoSuggestionsFunc(),
|
||||
HandleConfirm: func(repository string) error {
|
||||
return gui.c.WithWaitingStatus(gui.c.Tr.LcSelectingRemote, func() error {
|
||||
// `repository` is something like 'jesseduffield/lazygit'
|
||||
_, err := gui.git.Gh.SetBaseRepo(repository)
|
||||
if err != nil {
|
||||
return gui.c.Error(err)
|
||||
}
|
||||
|
||||
if err := gui.setGithubPullRequests(); err != nil {
|
||||
return gui.c.Error(err)
|
||||
}
|
||||
|
||||
// calling refreshBranches explicitly because it may have taken
|
||||
// a while for the user to submit their response.
|
||||
gui.refreshBranches()
|
||||
|
||||
return nil
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) setGithubPullRequests() error {
|
||||
prs, err := gui.git.Gh.GithubMostRecentPRs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gui.State.Model.PullRequests = prs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -420,7 +420,9 @@ type TranslationSet struct {
|
|||
LcBuildingPatch string
|
||||
LcViewCommits string
|
||||
MinGitVersionError string
|
||||
FailedToObtainGitVersionError string
|
||||
MinGhVersionError string
|
||||
FailedToObtainGhVersionError string
|
||||
LcRunningCustomCommandStatus string
|
||||
LcSubmoduleStashAndReset string
|
||||
LcAndResetSubmodules string
|
||||
|
@ -1000,7 +1002,7 @@ func EnglishTranslationSet() TranslationSet {
|
|||
LcPrevScreenMode: "prev screen mode",
|
||||
LcStartSearch: "start search",
|
||||
LcSelectingRemote: "selecting remote",
|
||||
SelectRemoteRepository: "select base remote repository",
|
||||
SelectRemoteRepository: "Select GitHub base remote repository (for PRs)",
|
||||
Panel: "Panel",
|
||||
Keybindings: "Keybindings",
|
||||
LcRenameBranch: "rename branch",
|
||||
|
@ -1065,6 +1067,8 @@ func EnglishTranslationSet() TranslationSet {
|
|||
LcViewCommits: "view commits",
|
||||
MinGitVersionError: "Git version must be at least 2.0 (i.e. from 2014 onwards). Please upgrade your git version. Alternatively raise an issue at https://github.com/jesseduffield/lazygit/issues for lazygit to be more backwards compatible.",
|
||||
MinGhVersionError: "GH version must be at least 2.0. Please upgrade your gh version. Alternatively raise an issue at https://github.com/jesseduffield/lazygit/issues for lazygit to be more backwards compatible.",
|
||||
FailedToObtainGitVersionError: "Failed to obtain git version. Output from running 'git --version' was: %s",
|
||||
FailedToObtainGhVersionError: "Failed to obtain gh version. Output from running 'gh --version' was: %s",
|
||||
LcRunningCustomCommandStatus: "running custom command",
|
||||
LcSubmoduleStashAndReset: "stash uncommitted submodule changes and update",
|
||||
LcAndResetSubmodules: "and reset submodules",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue