show github pr number in branches list

This commit is contained in:
mjarkk 2021-07-28 22:01:35 +02:00
parent de5133ff90
commit c295deaa81
23 changed files with 360 additions and 101 deletions

View file

@ -39,8 +39,8 @@
<pre> <pre>
<kbd>space</kbd>: checkout <kbd>space</kbd>: checkout
<kbd>o</kbd>: create pull request <kbd>o</kbd>: create / show pull request
<kbd>O</kbd>: create pull request options <kbd>O</kbd>: create / show pull request options
<kbd>ctrl+y</kbd>: copy pull request URL to clipboard <kbd>ctrl+y</kbd>: copy pull request URL to clipboard
<kbd>c</kbd>: checkout by name <kbd>c</kbd>: checkout by name
<kbd>F</kbd>: force checkout <kbd>F</kbd>: force checkout

View file

@ -39,7 +39,7 @@
<pre> <pre>
<kbd>space</kbd>: uitchecken <kbd>space</kbd>: uitchecken
<kbd>o</kbd>: maak een pull-request <kbd>o</kbd>: maak of laat een pull-request zien
<kbd>O</kbd>: bekijk opties voor pull-aanvraag <kbd>O</kbd>: bekijk opties voor pull-aanvraag
<kbd>ctrl+y</kbd>: kopieer de URL van het pull-verzoek naar het klembord <kbd>ctrl+y</kbd>: kopieer de URL van het pull-verzoek naar het klembord
<kbd>c</kbd>: uitchecken bij naam <kbd>c</kbd>: uitchecken bij naam

View file

@ -10,6 +10,7 @@ import (
"github.com/go-errors/errors" "github.com/go-errors/errors"
gogit "github.com/jesseduffield/go-git/v5" gogit "github.com/jesseduffield/go-git/v5"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/commands/patch" "github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
@ -39,6 +40,8 @@ type GitCommand struct {
// Push to current determines whether the user has configured to push to the remote branch of the same name as the current or not // Push to current determines whether the user has configured to push to the remote branch of the same name as the current or not
PushToCurrent bool PushToCurrent bool
GithubRecentPRs map[string]models.GithubPullRequest
} }
// NewGitCommand it runs git commands // NewGitCommand it runs git commands

65
pkg/commands/github.go Normal file
View file

@ -0,0 +1,65 @@
package commands
import (
"encoding/json"
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/models"
)
func (c *GitCommand) GithubMostRecentPRs() map[string]models.GithubPullRequest {
commandOutput, err := c.OSCommand.RunCommandWithOutput("gh pr list --limit 50 --state all --json state,url,number,headRefName,headRepositoryOwner")
if err != nil {
fmt.Println(1, err)
return nil
}
prs := []models.GithubPullRequest{}
err = json.Unmarshal([]byte(commandOutput), &prs)
if err != nil {
fmt.Println(2, err)
return nil
}
res := map[string]models.GithubPullRequest{}
for _, pr := range prs {
res[pr.HeadRepositoryOwner.Login+":"+pr.HeadRefName] = pr
}
return res
}
func (c *GitCommand) InjectGithubPullRequests(prs map[string]models.GithubPullRequest, branches []*models.Branch) bool {
if len(prs) == 0 {
return false
}
remotesToOwnersMap, _ := c.GetRemotesToOwnersMap()
if len(remotesToOwnersMap) == 0 {
return false
}
foundBranchWithGithubPullRequest := false
for _, branch := range branches {
if branch.UpstreamName == "" {
continue
}
remoteAndName := strings.SplitN(branch.UpstreamName, "/", 2)
owner, foundRemoteOwner := remotesToOwnersMap[remoteAndName[0]]
if len(remoteAndName) != 2 || !foundRemoteOwner {
continue
}
pr, hasPr := prs[owner+":"+remoteAndName[1]]
if !hasPr {
continue
}
foundBranchWithGithubPullRequest = true
branch.PR = &pr
}
return foundBranchWithGithubPullRequest
}

View file

@ -0,0 +1,75 @@
package commands
import (
"os/exec"
"testing"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/secureexec"
"github.com/stretchr/testify/assert"
)
func TestGithubMostRecentPRs(t *testing.T) {
scenarios := []struct {
testName string
response string
expect map[string]models.GithubPullRequest
}{
{
"no response",
"",
nil,
},
{
"error response",
"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`",
nil,
},
{
"empty response",
"[]",
map[string]models.GithubPullRequest{},
},
{
"response with data",
`[{
"headRefName": "command-log-2",
"number": 1249,
"state": "MERGED",
"url": "https://github.com/jesseduffield/lazygit/pull/1249",
"headRepositoryOwner": {
"id": "MDQ6VXNlcjg0NTY2MzM=",
"name": "Jesse Duffield",
"login": "jesseduffield"
}
}]`,
map[string]models.GithubPullRequest{
"jesseduffield:command-log-2": {
HeadRefName: "command-log-2",
Number: 1249,
State: "MERGED",
Url: "https://github.com/jesseduffield/lazygit/pull/1249",
HeadRepositoryOwner: models.GithubRepositoryOwner{
ID: "MDQ6VXNlcjg0NTY2MzM=",
Name: "Jesse Duffield",
Login: "jesseduffield",
},
},
},
},
}
for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) {
gitCmd := NewDummyGitCommand()
gitCmd.OSCommand.Command = func(cmd string, args ...string) *exec.Cmd {
assert.EqualValues(t, "gh", cmd)
assert.EqualValues(t, []string{"pr", "list", "--limit", "50", "--state", "all", "--json", "state,url,number,headRefName,headRepositoryOwner"}, args)
return secureexec.Command("echo", s.response)
}
res := gitCmd.GithubMostRecentPRs()
assert.Equal(t, s.expect, res)
})
}
}

View file

@ -99,8 +99,8 @@ func (b *BranchListBuilder) obtainBranches() []*models.Branch {
} }
// Build the list of branches for the current repo // Build the list of branches for the current repo
func (b *BranchListBuilder) Build() []*models.Branch { func (b *BranchListBuilder) Build() (branches []*models.Branch, branchesWithGithubPullRequests bool) {
branches := b.obtainBranches() branches = b.obtainBranches()
reflogBranches := b.obtainReflogBranches() reflogBranches := b.obtainReflogBranches()
@ -138,9 +138,17 @@ outer:
if err != nil { if err != nil {
panic(err) panic(err)
} }
branches = append([]*models.Branch{{Name: currentBranchName, DisplayName: currentBranchDisplayName, Head: true, Recency: " *"}}, branches...) branches = append([]*models.Branch{{
Name: currentBranchName,
DisplayName: currentBranchDisplayName,
Head: true,
Recency: " *",
}}, branches...)
} }
return branches
branchesWithGithubPullRequests = b.GitCommand.InjectGithubPullRequests(b.GitCommand.GithubRecentPRs, branches)
return
} }
// TODO: only look at the new reflog commits, and otherwise store the recencies in // TODO: only look at the new reflog commits, and otherwise store the recencies in

View file

@ -11,6 +11,7 @@ type Branch struct {
Pullables string Pullables string
UpstreamName string UpstreamName string
Head bool Head bool
PR *GithubPullRequest
} }
func (b *Branch) RefName() string { func (b *Branch) RefName() string {

View file

@ -0,0 +1,15 @@
package models
type GithubPullRequest struct {
HeadRefName string `json:"headRefName"`
Number int `json:"number"`
State string `json:"state"` // "MERGED", "OPEN", "CLOSED"
Url string `json:"url"`
HeadRepositoryOwner GithubRepositoryOwner `json:"headRepositoryOwner"`
}
type GithubRepositoryOwner struct {
ID string `json:"id"`
Name string `json:"name"`
Login string `json:"login"`
}

View file

@ -153,34 +153,9 @@ func (pr *PullRequest) getPullRequestURL(from string, to string) (string, error)
return "", errors.New(pr.GitCommand.Tr.UnsupportedGitService) return "", errors.New(pr.GitCommand.Tr.UnsupportedGitService)
} }
repoInfo := getRepoInfoFromURL(repoURL) repoInfo := GetRepoInfoFromURL(repoURL)
pullRequestURL := gitService.PullRequestURL(repoInfo.Owner, repoInfo.Repository, from, to) pullRequestURL := gitService.PullRequestURL(repoInfo.Owner, repoInfo.Repository, from, to)
return pullRequestURL, nil return pullRequestURL, nil
} }
func getRepoInfoFromURL(url string) *RepoInformation {
isHTTP := strings.HasPrefix(url, "http")
if isHTTP {
splits := strings.Split(url, "/")
owner := strings.Join(splits[3:len(splits)-1], "/")
repo := strings.TrimSuffix(splits[len(splits)-1], ".git")
return &RepoInformation{
Owner: owner,
Repository: repo,
}
}
tmpSplit := strings.Split(url, ":")
splits := strings.Split(tmpSplit[1], "/")
owner := strings.Join(splits[0:len(splits)-1], "/")
repo := strings.TrimSuffix(splits[len(splits)-1], ".git")
return &RepoInformation{
Owner: owner,
Repository: repo,
}
}

View file

@ -38,7 +38,7 @@ func TestGetRepoInfoFromURL(t *testing.T) {
for _, s := range scenarios { for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
s.test(getRepoInfoFromURL(s.repoURL)) s.test(GetRepoInfoFromURL(s.repoURL))
}) })
} }
} }

View file

@ -2,6 +2,7 @@ package commands
import ( import (
"fmt" "fmt"
"strings"
) )
func (c *GitCommand) AddRemote(name string, url string) error { func (c *GitCommand) AddRemote(name string, url string) error {
@ -39,3 +40,66 @@ func (c *GitCommand) CheckRemoteBranchExists(branchName string) bool {
func (c *GitCommand) GetRemoteURL() string { func (c *GitCommand) GetRemoteURL() string {
return c.GetConfigValue("remote.origin.url") return c.GetConfigValue("remote.origin.url")
} }
func (c *GitCommand) GetRemoteURLs() (map[string]string, error) {
res := map[string]string{}
out, err := c.OSCommand.RunCommandWithOutput("git remote -v")
if err != nil {
return nil, err
}
lines := strings.Split(strings.TrimSpace(out), "\n")
for _, line := range lines {
lineParts := strings.Split(line, "\t")
if len(lineParts) < 2 {
continue
}
name := lineParts[0] // "origin"
for _, mightBeUrl := range lineParts[1:] {
if len(mightBeUrl) > 0 {
// mightBeUrl = "git@github.com:jesseduffield/lazygit.git (fetch)"
res[name] = strings.SplitN(mightBeUrl, " ", 2)[0]
break
}
}
}
return res, nil
}
func GetRepoInfoFromURL(url string) *RepoInformation {
isHTTP := strings.HasPrefix(url, "http")
if isHTTP {
splits := strings.Split(url, "/")
owner := strings.Join(splits[3:len(splits)-1], "/")
repo := strings.TrimSuffix(splits[len(splits)-1], ".git")
return &RepoInformation{
Owner: owner,
Repository: repo,
}
}
tmpSplit := strings.Split(url, ":")
splits := strings.Split(tmpSplit[1], "/")
owner := strings.Join(splits[0:len(splits)-1], "/")
repo := strings.TrimSuffix(splits[len(splits)-1], ".git")
return &RepoInformation{
Owner: owner,
Repository: repo,
}
}
func (c *GitCommand) GetRemotesToOwnersMap() (map[string]string, error) {
remotes, err := c.GetRemoteURLs()
if err != nil {
return nil, err
}
res := map[string]string{}
for remoteName, remoteUrl := range remotes {
res[remoteName] = GetRepoInfoFromURL(remoteUrl).Owner
}
return res, nil
}

View file

@ -192,19 +192,19 @@ type KeybindingFilesConfig struct {
} }
type KeybindingBranchesConfig struct { type KeybindingBranchesConfig struct {
CreatePullRequest string `yaml:"createPullRequest"` CreateOrShowPullRequest string `yaml:"createPullRequest"`
ViewPullRequestOptions string `yaml:"viewPullRequestOptions"` ViewPullRequestOptions string `yaml:"viewPullRequestOptions"`
CopyPullRequestURL string `yaml:"copyPullRequestURL"` CopyPullRequestURL string `yaml:"copyPullRequestURL"`
CheckoutBranchByName string `yaml:"checkoutBranchByName"` CheckoutBranchByName string `yaml:"checkoutBranchByName"`
ForceCheckoutBranch string `yaml:"forceCheckoutBranch"` ForceCheckoutBranch string `yaml:"forceCheckoutBranch"`
RebaseBranch string `yaml:"rebaseBranch"` RebaseBranch string `yaml:"rebaseBranch"`
RenameBranch string `yaml:"renameBranch"` RenameBranch string `yaml:"renameBranch"`
MergeIntoCurrentBranch string `yaml:"mergeIntoCurrentBranch"` MergeIntoCurrentBranch string `yaml:"mergeIntoCurrentBranch"`
ViewGitFlowOptions string `yaml:"viewGitFlowOptions"` ViewGitFlowOptions string `yaml:"viewGitFlowOptions"`
FastForward string `yaml:"fastForward"` FastForward string `yaml:"fastForward"`
PushTag string `yaml:"pushTag"` PushTag string `yaml:"pushTag"`
SetUpstream string `yaml:"setUpstream"` SetUpstream string `yaml:"setUpstream"`
FetchRemote string `yaml:"fetchRemote"` FetchRemote string `yaml:"fetchRemote"`
} }
type KeybindingCommitsConfig struct { type KeybindingCommitsConfig struct {
@ -436,19 +436,19 @@ func GetDefaultConfig() *UserConfig {
OpenMergeTool: "M", OpenMergeTool: "M",
}, },
Branches: KeybindingBranchesConfig{ Branches: KeybindingBranchesConfig{
CopyPullRequestURL: "<c-y>", CopyPullRequestURL: "<c-y>",
CreatePullRequest: "o", CreateOrShowPullRequest: "o",
ViewPullRequestOptions: "O", ViewPullRequestOptions: "O",
CheckoutBranchByName: "c", CheckoutBranchByName: "c",
ForceCheckoutBranch: "F", ForceCheckoutBranch: "F",
RebaseBranch: "r", RebaseBranch: "r",
RenameBranch: "R", RenameBranch: "R",
MergeIntoCurrentBranch: "M", MergeIntoCurrentBranch: "M",
ViewGitFlowOptions: "i", ViewGitFlowOptions: "i",
FastForward: "f", FastForward: "f",
PushTag: "P", PushTag: "P",
SetUpstream: "u", SetUpstream: "u",
FetchRemote: "f", FetchRemote: "f",
}, },
Commits: KeybindingCommitsConfig{ Commits: KeybindingCommitsConfig{
SquashDown: "s", SquashDown: "s",

View file

@ -68,7 +68,7 @@ func (gui *Gui) refreshBranches() {
if err != nil { if err != nil {
_ = gui.surfaceError(err) _ = gui.surfaceError(err)
} }
gui.State.Branches = builder.Build() gui.State.Branches, gui.State.BranchesWithGithubPullRequests = builder.Build()
if err := gui.postRefreshUpdate(gui.State.Contexts.Branches); err != nil { if err := gui.postRefreshUpdate(gui.State.Contexts.Branches); err != nil {
gui.Log.Error(err) gui.Log.Error(err)
@ -77,6 +77,13 @@ func (gui *Gui) refreshBranches() {
gui.refreshStatus() gui.refreshStatus()
} }
func (gui *Gui) refreshGithubPullRequests() {
prs := gui.GitCommand.GithubMostRecentPRs()
if len(prs) > 0 {
gui.GitCommand.GithubRecentPRs = prs
}
}
// specific functions // specific functions
func (gui *Gui) handleBranchPress() error { func (gui *Gui) handleBranchPress() error {
@ -90,19 +97,22 @@ func (gui *Gui) handleBranchPress() error {
return gui.handleCheckoutRef(branch.Name, handleCheckoutRefOptions{span: gui.Tr.Spans.CheckoutBranch}) return gui.handleCheckoutRef(branch.Name, handleCheckoutRefOptions{span: gui.Tr.Spans.CheckoutBranch})
} }
func (gui *Gui) handleCreatePullRequestPress() error { func (gui *Gui) handleCreateOrShowPullRequestPress() error {
branch := gui.getSelectedBranch() branch := gui.getSelectedBranch()
if branch.PR != nil {
return gui.OSCommand.OpenLink(branch.PR.Url)
}
return gui.createPullRequest(branch.Name, "") return gui.createPullRequest(branch.Name, "")
} }
func (gui *Gui) handleCreatePullRequestMenu() error { func (gui *Gui) handleCreateOrOpenPullRequestMenu() error {
selectedBranch := gui.getSelectedBranch() selectedBranch := gui.getSelectedBranch()
if selectedBranch == nil { if selectedBranch == nil {
return nil return nil
} }
checkedOutBranch := gui.getCheckedOutBranch() checkedOutBranch := gui.getCheckedOutBranch()
return gui.createPullRequestMenu(selectedBranch, checkedOutBranch) return gui.createOrOpenPullRequestMenu(selectedBranch, checkedOutBranch)
} }
func (gui *Gui) handleCopyPullRequestURLPress() error { func (gui *Gui) handleCopyPullRequestURLPress() error {

View file

@ -61,12 +61,23 @@ func (gui *Gui) handleCommitSelect() error {
func (gui *Gui) refreshReflogCommitsConsideringStartup() { func (gui *Gui) refreshReflogCommitsConsideringStartup() {
switch gui.State.StartupStage { switch gui.State.StartupStage {
case INITIAL: case INITIAL:
var wg sync.WaitGroup
wg.Add(1)
go utils.Safe(func() { go utils.Safe(func() {
_ = gui.refreshReflogCommits() _ = gui.refreshReflogCommits()
gui.refreshBranches() gui.refreshBranches()
gui.State.StartupStage = COMPLETE gui.State.StartupStage = COMPLETE
wg.Done()
})
go utils.Safe(func() {
// The github cli can be quite slow so we load the github PRs sparately
gui.refreshGithubPullRequests()
wg.Wait()
gui.State.BranchesWithGithubPullRequests = gui.GitCommand.InjectGithubPullRequests(gui.GitCommand.GithubRecentPRs, gui.State.Branches)
_ = gui.postRefreshUpdate(gui.State.Contexts.Branches)
gui.refreshStatus()
}) })
case COMPLETE: case COMPLETE:
_ = gui.refreshReflogCommits() _ = gui.refreshReflogCommits()
} }

View file

@ -289,12 +289,13 @@ type guiMutexes struct {
type guiState struct { type guiState struct {
// the file panels (files and commit files) can render as a tree, so we have // the file panels (files and commit files) can render as a tree, so we have
// managers for them which handle rendering a flat list of files in tree form // managers for them which handle rendering a flat list of files in tree form
FileManager *filetree.FileManager FileManager *filetree.FileManager
CommitFileManager *filetree.CommitFileManager CommitFileManager *filetree.CommitFileManager
Submodules []*models.SubmoduleConfig Submodules []*models.SubmoduleConfig
Branches []*models.Branch Branches []*models.Branch
Commits []*models.Commit BranchesWithGithubPullRequests bool
StashEntries []*models.StashEntry Commits []*models.Commit
StashEntries []*models.StashEntry
// Suggestions will sometimes appear when typing into a prompt // Suggestions will sometimes appear when typing into a prompt
Suggestions []*types.Suggestion Suggestions []*types.Suggestion
// FilteredReflogCommits are the ones that appear in the reflog panel. // FilteredReflogCommits are the ones that appear in the reflog panel.

View file

@ -541,16 +541,16 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
{ {
ViewName: "branches", ViewName: "branches",
Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)},
Key: gui.getKey(config.Branches.CreatePullRequest), Key: gui.getKey(config.Branches.CreateOrShowPullRequest),
Handler: gui.handleCreatePullRequestPress, Handler: gui.handleCreateOrShowPullRequestPress,
Description: gui.Tr.LcCreatePullRequest, Description: gui.Tr.LcCreateOrShowPullRequest,
}, },
{ {
ViewName: "branches", ViewName: "branches",
Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)},
Key: gui.getKey(config.Branches.ViewPullRequestOptions), Key: gui.getKey(config.Branches.ViewPullRequestOptions),
Handler: gui.handleCreatePullRequestMenu, Handler: gui.handleCreateOrOpenPullRequestMenu,
Description: gui.Tr.LcCreatePullRequestOptions, Description: gui.Tr.LcCreateOrOpenPullRequestOptions,
OpensMenu: true, OpensMenu: true,
}, },
{ {

View file

@ -70,7 +70,12 @@ func (gui *Gui) branchesListContext() *ListContext {
Gui: gui, Gui: gui,
ResetMainViewOriginOnFocus: true, ResetMainViewOriginOnFocus: true,
GetDisplayStrings: func() [][]string { GetDisplayStrings: func() [][]string {
return presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref) return presentation.GetBranchListDisplayStrings(
gui.State.Branches,
gui.State.ScreenMode != SCREEN_NORMAL,
gui.State.Modes.Diffing.Ref,
gui.State.BranchesWithGithubPullRequests,
)
}, },
SelectedItem: func() (ListItem, bool) { SelectedItem: func() (ListItem, bool) {
item := gui.getSelectedBranch() item := gui.getSelectedBranch()

View file

@ -2,6 +2,7 @@ package presentation
import ( import (
"fmt" "fmt"
"strconv"
"strings" "strings"
"github.com/fatih/color" "github.com/fatih/color"
@ -10,19 +11,19 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
) )
func GetBranchListDisplayStrings(branches []*models.Branch, fullDescription bool, diffName string) [][]string { func GetBranchListDisplayStrings(branches []*models.Branch, fullDescription bool, diffName string, showGithub bool) [][]string {
lines := make([][]string, len(branches)) lines := make([][]string, len(branches))
for i := range branches { for i := range branches {
diffed := branches[i].Name == diffName diffed := branches[i].Name == diffName
lines[i] = getBranchDisplayStrings(branches[i], fullDescription, diffed) lines[i] = getBranchDisplayStrings(branches[i], fullDescription, diffed, showGithub)
} }
return lines return lines
} }
// getBranchDisplayStrings returns the display string of branch // getBranchDisplayStrings returns the display string of branch
func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool) []string { func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed, showGithub bool) []string {
displayName := b.Name displayName := b.Name
if b.DisplayName != "" { if b.DisplayName != "" {
displayName = b.DisplayName displayName = b.DisplayName
@ -42,11 +43,26 @@ func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool
recencyColor = color.FgGreen recencyColor = color.FgGreen
} }
if fullDescription { res := []string{utils.ColoredString(b.Recency, recencyColor)}
return []string{utils.ColoredString(b.Recency, recencyColor), coloredName, utils.ColoredString(b.UpstreamName, color.FgYellow)} if showGithub {
if b.PR != nil {
colour := color.FgMagenta // = state MERGED
switch b.PR.State {
case "OPEN":
colour = color.FgGreen
case "CLOSED":
colour = color.FgRed
}
res = append(res, utils.ColoredString("#"+strconv.Itoa(b.PR.Number), colour))
} else {
res = append(res, "")
}
} }
return []string{utils.ColoredString(b.Recency, recencyColor), coloredName} if fullDescription {
return append(res, coloredName, utils.ColoredString(b.UpstreamName, color.FgYellow))
}
return append(res, coloredName)
} }
// GetBranchColor branch color // GetBranchColor branch color

View file

@ -2,13 +2,14 @@ package gui
import ( import (
"fmt" "fmt"
"strconv"
"github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
) )
func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutBranch *models.Branch) error { func (gui *Gui) createOrOpenPullRequestMenu(selectedBranch *models.Branch, checkedOutBranch *models.Branch) error {
menuItems := make([]*menuItem, 0, 4) menuItems := make([]*menuItem, 0, 4)
fromToDisplayStrings := func(from string, to string) []string { fromToDisplayStrings := func(from string, to string) []string {
@ -38,6 +39,15 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB
} }
} }
if selectedBranch.PR != nil {
menuItems = append(menuItems, &menuItem{
displayString: "open #" + strconv.Itoa(selectedBranch.PR.Number),
onPress: func() error {
return gui.OSCommand.OpenLink(selectedBranch.PR.Url)
},
})
}
if selectedBranch != checkedOutBranch { if selectedBranch != checkedOutBranch {
menuItems = append(menuItems, menuItems = append(menuItems,
&menuItem{ &menuItem{
@ -52,7 +62,7 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB
menuItems = append(menuItems, menuItemsForBranch(selectedBranch)...) menuItems = append(menuItems, menuItemsForBranch(selectedBranch)...)
return gui.createMenu(fmt.Sprintf(gui.Tr.CreatePullRequestOptions), menuItems, createMenuOptions{showCancel: true}) return gui.createMenu(fmt.Sprintf(gui.Tr.CreateOrOpenPullRequestOptions), menuItems, createMenuOptions{showCancel: true})
} }
func (gui *Gui) createPullRequest(from string, to string) error { func (gui *Gui) createPullRequest(from string, to string) error {
@ -61,7 +71,7 @@ func (gui *Gui) createPullRequest(from string, to string) error {
if err != nil { if err != nil {
return gui.surfaceError(err) return gui.surfaceError(err)
} }
gui.OnRunCommand(oscommands.NewCmdLogEntry(fmt.Sprintf(gui.Tr.CreatingPullRequestAtUrl, url), gui.Tr.CreatePullRequest, false)) gui.OnRunCommand(oscommands.NewCmdLogEntry(fmt.Sprintf(gui.Tr.CreatingPullRequestAtUrl, url), gui.Tr.CreateOrShowPullRequest, false))
return nil return nil
} }

View file

@ -176,7 +176,7 @@ func chineseTranslationSet() TranslationSet {
SwitchRepo: `切换到最近的仓库`, SwitchRepo: `切换到最近的仓库`,
LcAllBranchesLogGraph: `显示所有分支日志`, LcAllBranchesLogGraph: `显示所有分支日志`,
UnsupportedGitService: `不支持的git服务`, UnsupportedGitService: `不支持的git服务`,
LcCreatePullRequest: `创建pull请求`, LcCreateOrShowPullRequest: `创建pull请求`,
LcCopyPullRequestURL: `将拉取请求URL复制到剪贴板`, LcCopyPullRequestURL: `将拉取请求URL复制到剪贴板`,
NoBranchOnRemote: `该分支在远程上不存在。您需要先将其推送到远程.`, NoBranchOnRemote: `该分支在远程上不存在。您需要先将其推送到远程.`,
LcFetch: `fetch`, LcFetch: `fetch`,

View file

@ -154,7 +154,7 @@ func dutchTranslationSet() TranslationSet {
SwitchRepo: "wissel naar een recente repo", SwitchRepo: "wissel naar een recente repo",
LcAllBranchesLogGraph: `alle logs van de branch laten zien`, LcAllBranchesLogGraph: `alle logs van de branch laten zien`,
UnsupportedGitService: `Niet-ondersteunde git-service`, UnsupportedGitService: `Niet-ondersteunde git-service`,
LcCreatePullRequest: `maak een pull-request`, LcCreateOrShowPullRequest: `maak of laat een pull-request zien`,
LcCopyPullRequestURL: `kopieer de URL van het pull-verzoek naar het klembord`, LcCopyPullRequestURL: `kopieer de URL van het pull-verzoek naar het klembord`,
NoBranchOnRemote: `Deze branch bestaat niet op de remote. U moet het eerst naar de remote pushen.`, NoBranchOnRemote: `Deze branch bestaat niet op de remote. U moet het eerst naar de remote pushen.`,
LcFetch: `fetch`, LcFetch: `fetch`,
@ -396,7 +396,7 @@ func dutchTranslationSet() TranslationSet {
LcInitSubmodule: "initialiseer submodule", LcInitSubmodule: "initialiseer submodule",
LcViewBulkSubmoduleOptions: "bekijk bulk submodule opties", LcViewBulkSubmoduleOptions: "bekijk bulk submodule opties",
LcViewStashFiles: "bekijk bestanden van stash entry", LcViewStashFiles: "bekijk bestanden van stash entry",
CreatePullRequestOptions: "Bekijk opties voor pull-aanvraag", CreateOrOpenPullRequestOptions: "Bekijk opties voor pull-aanvraag",
LcCreatePullRequestOptions: "bekijk opties voor pull-aanvraag", LcCreateOrOpenPullRequestOptions: "bekijk opties voor pull-aanvraag",
} }
} }

View file

@ -169,7 +169,7 @@ type TranslationSet struct {
SwitchRepo string SwitchRepo string
LcAllBranchesLogGraph string LcAllBranchesLogGraph string
UnsupportedGitService string UnsupportedGitService string
LcCreatePullRequest string LcCreateOrShowPullRequest string
LcCopyPullRequestURL string LcCopyPullRequestURL string
NoBranchOnRemote string NoBranchOnRemote string
LcFetch string LcFetch string
@ -454,11 +454,11 @@ type TranslationSet struct {
ToggleWhitespaceInDiffView string ToggleWhitespaceInDiffView string
IgnoringWhitespaceInDiffView string IgnoringWhitespaceInDiffView string
ShowingWhitespaceInDiffView string ShowingWhitespaceInDiffView string
CreatePullRequestOptions string CreateOrOpenPullRequestOptions string
LcCreatePullRequestOptions string LcCreateOrOpenPullRequestOptions string
LcDefaultBranch string LcDefaultBranch string
LcSelectBranch string LcSelectBranch string
CreatePullRequest string CreateOrShowPullRequest string
CreatingPullRequestAtUrl string CreatingPullRequestAtUrl string
Spans Spans Spans Spans
} }
@ -720,7 +720,7 @@ func englishTranslationSet() TranslationSet {
SwitchRepo: `switch to a recent repo`, SwitchRepo: `switch to a recent repo`,
LcAllBranchesLogGraph: `show all branch logs`, LcAllBranchesLogGraph: `show all branch logs`,
UnsupportedGitService: `Unsupported git service`, UnsupportedGitService: `Unsupported git service`,
LcCreatePullRequest: `create pull request`, LcCreateOrShowPullRequest: `create / show pull request`,
LcCopyPullRequestURL: `copy pull request URL to clipboard`, LcCopyPullRequestURL: `copy pull request URL to clipboard`,
NoBranchOnRemote: `This branch doesn't exist on remote. You need to push it to remote first.`, NoBranchOnRemote: `This branch doesn't exist on remote. You need to push it to remote first.`,
LcFetch: `fetch`, LcFetch: `fetch`,
@ -1007,9 +1007,9 @@ func englishTranslationSet() TranslationSet {
ToggleWhitespaceInDiffView: "Toggle whether or not whitespace changes are shown in the diff view", ToggleWhitespaceInDiffView: "Toggle whether or not whitespace changes are shown in the diff view",
IgnoringWhitespaceInDiffView: "Whitespace will be ignored in the diff view", IgnoringWhitespaceInDiffView: "Whitespace will be ignored in the diff view",
ShowingWhitespaceInDiffView: "Whitespace will be shown in the diff view", ShowingWhitespaceInDiffView: "Whitespace will be shown in the diff view",
CreatePullRequest: "Create pull request", CreateOrShowPullRequest: "Create / show pull request",
CreatePullRequestOptions: "Create pull request options", CreateOrOpenPullRequestOptions: "Create / show pull request options",
LcCreatePullRequestOptions: "create pull request options", LcCreateOrOpenPullRequestOptions: "create / show pull request options",
LcDefaultBranch: "default branch", LcDefaultBranch: "default branch",
LcSelectBranch: "select branch", LcSelectBranch: "select branch",
CreatingPullRequestAtUrl: "Creating pull request at URL: %s", CreatingPullRequestAtUrl: "Creating pull request at URL: %s",

View file

@ -127,7 +127,7 @@ func polishTranslationSet() TranslationSet {
ConfirmQuit: `Na pewno chcesz wyjść z programu?`, ConfirmQuit: `Na pewno chcesz wyjść z programu?`,
LcAllBranchesLogGraph: `pokazywać wszystkie logi branżowe`, LcAllBranchesLogGraph: `pokazywać wszystkie logi branżowe`,
UnsupportedGitService: `Nieobsługiwana usługa git`, UnsupportedGitService: `Nieobsługiwana usługa git`,
LcCreatePullRequest: `utwórz żądanie wyciągnięcia`, LcCreateOrShowPullRequest: `utwórz żądanie wyciągnięcia`,
LcCopyPullRequestURL: `skopiuj adres URL żądania ściągnięcia do schowka`, LcCopyPullRequestURL: `skopiuj adres URL żądania ściągnięcia do schowka`,
NoBranchOnRemote: `Ta gałąź nie istnieje na zdalnym. Najpierw musisz go odepchnąć na odległość.`, NoBranchOnRemote: `Ta gałąź nie istnieje na zdalnym. Najpierw musisz go odepchnąć na odległość.`,
LcFetch: `fetch`, LcFetch: `fetch`,
@ -255,7 +255,7 @@ func polishTranslationSet() TranslationSet {
PullRequestURLCopiedToClipboard: "URL żądania ściągnięcia skopiowany do schowka", PullRequestURLCopiedToClipboard: "URL żądania ściągnięcia skopiowany do schowka",
CommitMessageCopiedToClipboard: "Commit message skopiowany do schowka", CommitMessageCopiedToClipboard: "Commit message skopiowany do schowka",
LcCopiedToClipboard: "skopiowany do schowka", LcCopiedToClipboard: "skopiowany do schowka",
CreatePullRequestOptions: "Utwórz opcje żądania ściągnięcia", CreateOrOpenPullRequestOptions: "Utwórz opcje żądania ściągnięcia",
LcCreatePullRequestOptions: "utwórz opcje żądania ściągnięcia", LcCreateOrOpenPullRequestOptions: "utwórz opcje żądania ściągnięcia",
} }
} }