mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-28 10:16:22 -04:00
Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
759ddd3e80 | ||
|
|
b431a354aa | ||
|
|
24a3b815c5 | ||
|
|
7efb900336 | ||
|
|
ab8e1f0265 | ||
|
|
8cf3d8b269 | ||
|
|
e6b5fb93eb | ||
|
|
649a8b7276 | ||
|
|
345c533d64 | ||
|
|
5e542c3992 | ||
|
|
0b33634c73 | ||
|
|
8d6da58bfa | ||
|
|
cd6d92da1d | ||
|
|
46a333407d | ||
|
|
c3cf48cc49 | ||
|
|
949e131ebe |
@@ -145,11 +145,11 @@ func (self *RebaseCommands) InteractiveRebase(commits []*models.Commit, startIdx
|
||||
|
||||
baseHashOrRoot := getBaseHashOrRoot(commits, baseIndex)
|
||||
|
||||
changes := lo.Map(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) daemon.ChangeTodoAction {
|
||||
changes := lo.FilterMap(commits[startIdx:endIdx+1], func(commit *models.Commit, _ int) (daemon.ChangeTodoAction, bool) {
|
||||
return daemon.ChangeTodoAction{
|
||||
Hash: commit.Hash,
|
||||
NewAction: action,
|
||||
}
|
||||
}, !commit.IsMerge()
|
||||
})
|
||||
|
||||
self.os.LogCommand(logTodoChanges(changes), false)
|
||||
|
||||
@@ -70,8 +70,6 @@ func (self *ContextMgr) Push(c types.Context, opts ...types.OnFocusOpts) {
|
||||
return
|
||||
}
|
||||
|
||||
gui.resetHelpersAndControllers()
|
||||
|
||||
contextsToDeactivate, contextToActivate := self.pushToContextStack(c)
|
||||
|
||||
for _, contextToDeactivate := range contextsToDeactivate {
|
||||
|
||||
@@ -14,7 +14,6 @@ type ConfirmationContext struct {
|
||||
type ConfirmationContextState struct {
|
||||
OnConfirm func() error
|
||||
OnClose func() error
|
||||
Multiline bool
|
||||
}
|
||||
|
||||
var _ types.Context = (*ConfirmationContext)(nil)
|
||||
|
||||
@@ -730,11 +730,23 @@ func (self *BranchesController) createPullRequestMenu(selectedBranch *models.Bra
|
||||
{
|
||||
LabelColumns: fromToLabelColumns(branch.Name, self.c.Tr.SelectBranch),
|
||||
OnPress: func() error {
|
||||
if !branch.IsTrackingRemote() {
|
||||
return errors.New(self.c.Tr.PullRequestNoUpstream)
|
||||
}
|
||||
|
||||
if len(self.c.Model().Remotes) == 1 {
|
||||
toRemote := self.c.Model().Remotes[0].Name
|
||||
self.c.Log.Debugf("PR will target the only existing remote '%s'", toRemote)
|
||||
return self.promptForTargetBranchNameAndCreatePullRequest(branch, toRemote)
|
||||
}
|
||||
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: branch.Name + " →",
|
||||
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRemoteBranchesSuggestionsFunc("/"),
|
||||
HandleConfirm: func(targetBranchName string) error {
|
||||
return self.createPullRequest(branch.Name, targetBranchName)
|
||||
Title: self.c.Tr.SelectTargetRemote,
|
||||
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRemoteSuggestionsFunc(),
|
||||
HandleConfirm: func(toRemote string) error {
|
||||
self.c.Log.Debugf("PR will target remote '%s'", toRemote)
|
||||
|
||||
return self.promptForTargetBranchNameAndCreatePullRequest(branch, toRemote)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -764,6 +776,26 @@ func (self *BranchesController) createPullRequestMenu(selectedBranch *models.Bra
|
||||
return self.c.Menu(types.CreateMenuOptions{Title: fmt.Sprint(self.c.Tr.CreatePullRequestOptions), Items: menuItems})
|
||||
}
|
||||
|
||||
func (self *BranchesController) promptForTargetBranchNameAndCreatePullRequest(fromBranch *models.Branch, toRemote string) error {
|
||||
remoteDoesNotExist := lo.NoneBy(self.c.Model().Remotes, func(remote *models.Remote) bool {
|
||||
return remote.Name == toRemote
|
||||
})
|
||||
if remoteDoesNotExist {
|
||||
return fmt.Errorf(self.c.Tr.NoValidRemoteName, toRemote)
|
||||
}
|
||||
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: fmt.Sprintf("%s → %s/", fromBranch.UpstreamBranch, toRemote),
|
||||
FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRemoteBranchesForRemoteSuggestionsFunc(toRemote),
|
||||
HandleConfirm: func(toBranch string) error {
|
||||
self.c.Log.Debugf("PR will target branch '%s' on remote '%s'", toBranch, toRemote)
|
||||
return self.createPullRequest(fromBranch.UpstreamBranch, toBranch)
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *BranchesController) createPullRequest(from string, to string) error {
|
||||
url, err := self.c.Helpers().Host.GetPullRequestURL(from, to)
|
||||
if err != nil {
|
||||
|
||||
@@ -24,54 +24,20 @@ func NewConfirmationController(
|
||||
}
|
||||
|
||||
func (self *ConfirmationController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{}
|
||||
|
||||
if self.context().State.Multiline {
|
||||
bindings = append(bindings,
|
||||
&types.Binding{
|
||||
// Hard coding because this is always the button that adds a newline.
|
||||
Key: opts.GetKey("<enter>"),
|
||||
Handler: func() error {
|
||||
self.c.Log.Warn("In <enter> handler")
|
||||
self.c.Views().Confirmation.TextArea.TypeString("\n")
|
||||
self.c.Views().Confirmation.RenderTextArea()
|
||||
return nil
|
||||
},
|
||||
Description: self.c.Tr.Confirm,
|
||||
DisplayOnScreen: false,
|
||||
},
|
||||
&types.Binding{
|
||||
Key: opts.GetKey(opts.Config.Universal.ConfirmInEditor),
|
||||
Handler: func() error {
|
||||
self.c.Log.Warn("In <alt-enter> handler")
|
||||
return self.context().State.OnConfirm()
|
||||
},
|
||||
Description: self.c.Tr.Confirm,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
bindings = append(bindings,
|
||||
&types.Binding{
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
Handler: func() error {
|
||||
self.c.Log.Warn("In single-line confirm handler")
|
||||
return self.context().State.OnConfirm()
|
||||
},
|
||||
Description: self.c.Tr.Confirm,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
bindings = append(bindings,
|
||||
&types.Binding{
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||
Handler: func() error { return self.context().State.OnConfirm() },
|
||||
Description: self.c.Tr.Confirm,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||
Handler: func() error { return self.context().State.OnClose() },
|
||||
Description: self.c.Tr.CloseCancel,
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
&types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.TogglePanel),
|
||||
Handler: func() error {
|
||||
if len(self.c.Contexts().Suggestions.State.Suggestions) > 0 {
|
||||
@@ -88,7 +54,7 @@ func (self *ConfirmationController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
return nil
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return bindings
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/mattn/go-runewidth"
|
||||
)
|
||||
|
||||
@@ -157,14 +156,12 @@ func (self *ConfirmationHelper) getPopupPanelWidth() int {
|
||||
func (self *ConfirmationHelper) prepareConfirmationPanel(
|
||||
opts types.ConfirmOpts,
|
||||
) {
|
||||
self.c.Contexts().Confirmation.State.Multiline = opts.Multiline
|
||||
confirmationView := self.c.Views().Confirmation
|
||||
confirmationView.Title = opts.Title
|
||||
self.c.Views().Confirmation.Title = opts.Title
|
||||
// for now we do not support wrapping in our editor
|
||||
confirmationView.Wrap = !opts.Editable
|
||||
confirmationView.FgColor = theme.GocuiDefaultTextColor
|
||||
confirmationView.Mask = runeForMask(opts.Mask)
|
||||
confirmationView.SetOrigin(0, 0)
|
||||
self.c.Views().Confirmation.Wrap = !opts.Editable
|
||||
self.c.Views().Confirmation.FgColor = theme.GocuiDefaultTextColor
|
||||
self.c.Views().Confirmation.Mask = runeForMask(opts.Mask)
|
||||
self.c.Views().Confirmation.SetOrigin(0, 0)
|
||||
|
||||
suggestionsContext := self.c.Contexts().Suggestions
|
||||
suggestionsContext.State.FindSuggestions = opts.FindSuggestionsFunc
|
||||
@@ -209,7 +206,6 @@ func (self *ConfirmationHelper) CreatePopupPanel(ctx goContext.Context, opts typ
|
||||
self.prepareConfirmationPanel(
|
||||
types.ConfirmOpts{
|
||||
Title: opts.Title,
|
||||
Multiline: opts.Multiline,
|
||||
Prompt: opts.Prompt,
|
||||
FindSuggestionsFunc: opts.FindSuggestionsFunc,
|
||||
Editable: opts.Editable,
|
||||
@@ -217,14 +213,6 @@ func (self *ConfirmationHelper) CreatePopupPanel(ctx goContext.Context, opts typ
|
||||
})
|
||||
confirmationView := self.c.Views().Confirmation
|
||||
confirmationView.Editable = opts.Editable
|
||||
if opts.Multiline {
|
||||
confirmationView.Subtitle = utils.ResolvePlaceholderString(
|
||||
self.c.Tr.PressToSubmit,
|
||||
map[string]string{"Key": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor},
|
||||
)
|
||||
} else {
|
||||
confirmationView.Subtitle = ""
|
||||
}
|
||||
|
||||
if opts.Editable {
|
||||
textArea := confirmationView.TextArea
|
||||
@@ -375,16 +363,7 @@ func (self *ConfirmationHelper) resizeConfirmationPanel(parentPopupContext types
|
||||
prompt = self.c.Views().Confirmation.TextArea.GetContent()
|
||||
wrap = false
|
||||
}
|
||||
|
||||
multiline := self.c.Contexts().Confirmation.State.Multiline
|
||||
inputHeight := getMessageHeight(wrap, prompt, panelWidth)
|
||||
|
||||
minMultilineHeight := 5
|
||||
if multiline && inputHeight < minMultilineHeight {
|
||||
inputHeight = minMultilineHeight
|
||||
}
|
||||
|
||||
panelHeight := inputHeight + suggestionsViewHeight
|
||||
panelHeight := getMessageHeight(wrap, prompt, panelWidth) + suggestionsViewHeight
|
||||
x0, y0, x1, y1 := self.getPopupPanelDimensionsAux(panelWidth, panelHeight, parentPopupContext)
|
||||
confirmationViewBottom := y1 - suggestionsViewHeight
|
||||
_, _ = self.c.GocuiGui().SetView(self.c.Views().Confirmation.Name(), x0, y0, x1, confirmationViewBottom, 0)
|
||||
|
||||
@@ -162,10 +162,26 @@ func (self *SuggestionsHelper) getRemoteBranchNames(separator string) []string {
|
||||
})
|
||||
}
|
||||
|
||||
func (self *SuggestionsHelper) getRemoteBranchNamesForRemote(remoteName string) []string {
|
||||
remote, ok := lo.Find(self.c.Model().Remotes, func(remote *models.Remote) bool {
|
||||
return remote.Name == remoteName
|
||||
})
|
||||
if ok {
|
||||
return lo.Map(remote.Branches, func(branch *models.RemoteBranch, _ int) string {
|
||||
return branch.Name
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SuggestionsHelper) GetRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion {
|
||||
return FilterFunc(self.getRemoteBranchNames(separator), self.c.UserConfig().Gui.UseFuzzySearch())
|
||||
}
|
||||
|
||||
func (self *SuggestionsHelper) GetRemoteBranchesForRemoteSuggestionsFunc(remoteName string) func(string) []*types.Suggestion {
|
||||
return FilterFunc(self.getRemoteBranchNamesForRemote(remoteName), self.c.UserConfig().Gui.UseFuzzySearch())
|
||||
}
|
||||
|
||||
func (self *SuggestionsHelper) getTagNames() []string {
|
||||
return lo.Map(self.c.Model().Tags, func(tag *models.Tag, _ int) string {
|
||||
return tag.Name
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/types/enums"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context/traits"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
@@ -115,7 +116,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
},
|
||||
{
|
||||
Key: opts.GetKey(editCommitKey),
|
||||
Handler: self.withItems(self.edit),
|
||||
Handler: self.withItemsRange(self.edit),
|
||||
GetDisabledReason: self.require(
|
||||
self.itemRangeSelected(self.midRebaseCommandEnabled),
|
||||
),
|
||||
@@ -510,11 +511,25 @@ func (self *LocalCommitsController) drop(selectedCommits []*models.Commit, start
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) edit(selectedCommits []*models.Commit) error {
|
||||
func (self *LocalCommitsController) edit(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
|
||||
if self.isRebasing() {
|
||||
return self.updateTodos(todo.Edit, selectedCommits)
|
||||
}
|
||||
|
||||
commits := self.c.Model().Commits
|
||||
if !commits[endIdx].IsMerge() {
|
||||
selectionRangeAndMode := self.getSelectionRangeAndMode()
|
||||
err := self.c.Git().Rebase.InteractiveRebase(commits, startIdx, endIdx, todo.Edit)
|
||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
|
||||
err,
|
||||
types.RefreshOptions{
|
||||
Mode: types.BLOCK_UI, Then: func() error {
|
||||
self.restoreSelectionRangeAndMode(selectionRangeAndMode)
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return self.startInteractiveRebaseWithEdit(selectedCommits)
|
||||
}
|
||||
|
||||
@@ -532,10 +547,7 @@ func (self *LocalCommitsController) startInteractiveRebaseWithEdit(
|
||||
) error {
|
||||
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.EditCommit)
|
||||
selectedIdx, rangeStartIdx, rangeSelectMode := self.context().GetSelectionRangeAndMode()
|
||||
commits := self.c.Model().Commits
|
||||
selectedHash := commits[selectedIdx].Hash
|
||||
rangeStartHash := commits[rangeStartIdx].Hash
|
||||
selectionRangeAndMode := self.getSelectionRangeAndMode()
|
||||
err := self.c.Git().Rebase.EditRebase(commitsToEdit[len(commitsToEdit)-1].Hash)
|
||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
|
||||
err,
|
||||
@@ -554,23 +566,41 @@ func (self *LocalCommitsController) startInteractiveRebaseWithEdit(
|
||||
}
|
||||
}
|
||||
|
||||
// We need to select the same commit range again because after starting a rebase,
|
||||
// new lines can be added for update-ref commands in the TODO file, due to
|
||||
// stacked branches. So the selected commits may be in different positions in the list.
|
||||
_, newSelectedIdx, ok1 := lo.FindIndexOf(self.c.Model().Commits, func(c *models.Commit) bool {
|
||||
return c.Hash == selectedHash
|
||||
})
|
||||
_, newRangeStartIdx, ok2 := lo.FindIndexOf(self.c.Model().Commits, func(c *models.Commit) bool {
|
||||
return c.Hash == rangeStartHash
|
||||
})
|
||||
if ok1 && ok2 {
|
||||
self.context().SetSelectionRangeAndMode(newSelectedIdx, newRangeStartIdx, rangeSelectMode)
|
||||
}
|
||||
self.restoreSelectionRangeAndMode(selectionRangeAndMode)
|
||||
return nil
|
||||
}})
|
||||
})
|
||||
}
|
||||
|
||||
type SelectionRangeAndMode struct {
|
||||
selectedHash string
|
||||
rangeStartHash string
|
||||
mode traits.RangeSelectMode
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) getSelectionRangeAndMode() SelectionRangeAndMode {
|
||||
selectedIdx, rangeStartIdx, rangeSelectMode := self.context().GetSelectionRangeAndMode()
|
||||
commits := self.c.Model().Commits
|
||||
selectedHash := commits[selectedIdx].Hash
|
||||
rangeStartHash := commits[rangeStartIdx].Hash
|
||||
return SelectionRangeAndMode{selectedHash, rangeStartHash, rangeSelectMode}
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) restoreSelectionRangeAndMode(selectionRangeAndMode SelectionRangeAndMode) {
|
||||
// We need to select the same commit range again because after starting a rebase,
|
||||
// new lines can be added for update-ref commands in the TODO file, due to
|
||||
// stacked branches. So the selected commits may be in different positions in the list.
|
||||
_, newSelectedIdx, ok1 := lo.FindIndexOf(self.c.Model().Commits, func(c *models.Commit) bool {
|
||||
return c.Hash == selectionRangeAndMode.selectedHash
|
||||
})
|
||||
_, newRangeStartIdx, ok2 := lo.FindIndexOf(self.c.Model().Commits, func(c *models.Commit) bool {
|
||||
return c.Hash == selectionRangeAndMode.rangeStartHash
|
||||
})
|
||||
if ok1 && ok2 {
|
||||
self.context().SetSelectionRangeAndMode(newSelectedIdx, newRangeStartIdx, selectionRangeAndMode.mode)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) findCommitForQuickStartInteractiveRebase() (*models.Commit, error) {
|
||||
commit, index, ok := lo.FindIndexOf(self.c.Model().Commits, func(c *models.Commit) bool {
|
||||
return c.IsMerge() || c.Status == models.StatusMerged
|
||||
|
||||
@@ -107,7 +107,6 @@ func (self *PopupHandler) Confirm(opts types.ConfirmOpts) {
|
||||
func (self *PopupHandler) Prompt(opts types.PromptOpts) {
|
||||
self.createPopupPanelFn(context.Background(), types.CreatePopupPanelOpts{
|
||||
Title: opts.Title,
|
||||
Multiline: opts.Multiline,
|
||||
Prompt: opts.InitialContent,
|
||||
Editable: true,
|
||||
HandleConfirmPrompt: opts.HandleConfirm,
|
||||
|
||||
@@ -79,14 +79,6 @@ func (self *HandlerCreator) call(customCommand config.CustomCommand) func() erro
|
||||
}
|
||||
return self.inputPrompt(resolvedPrompt, wrappedF)
|
||||
}
|
||||
case "textbox":
|
||||
f = func() error {
|
||||
resolvedPrompt, err := self.resolver.resolvePrompt(&prompt, resolveTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return self.textboxPrompt(resolvedPrompt, wrappedF)
|
||||
}
|
||||
case "menu":
|
||||
f = func() error {
|
||||
resolvedPrompt, err := self.resolver.resolvePrompt(&prompt, resolveTemplate)
|
||||
@@ -138,19 +130,6 @@ func (self *HandlerCreator) inputPrompt(prompt *config.CustomCommandPrompt, wrap
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *HandlerCreator) textboxPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error {
|
||||
self.c.Prompt(types.PromptOpts{
|
||||
Title: prompt.Title,
|
||||
InitialContent: prompt.InitialValue,
|
||||
Multiline: true,
|
||||
HandleConfirm: func(str string) error {
|
||||
return wrappedF(str)
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *HandlerCreator) generateFindSuggestionsFunc(prompt *config.CustomCommandPrompt) (func(string) []*types.Suggestion, error) {
|
||||
if prompt.Suggestions.Preset != "" && prompt.Suggestions.Command != "" {
|
||||
return nil, fmt.Errorf(
|
||||
|
||||
@@ -153,7 +153,6 @@ type CreatePopupPanelOpts struct {
|
||||
HasLoader bool
|
||||
Editable bool
|
||||
Title string
|
||||
Multiline bool
|
||||
Prompt string
|
||||
HandleConfirm func() error
|
||||
HandleConfirmPrompt func(string) error
|
||||
@@ -167,7 +166,6 @@ type CreatePopupPanelOpts struct {
|
||||
|
||||
type ConfirmOpts struct {
|
||||
Title string
|
||||
Multiline bool
|
||||
Prompt string
|
||||
HandleConfirm func() error
|
||||
HandleClose func() error
|
||||
@@ -178,7 +176,6 @@ type ConfirmOpts struct {
|
||||
|
||||
type PromptOpts struct {
|
||||
Title string
|
||||
Multiline bool
|
||||
InitialContent string
|
||||
FindSuggestionsFunc func(string) []*Suggestion
|
||||
HandleConfirm func(string) error
|
||||
|
||||
+4
-2
@@ -555,7 +555,6 @@ type TranslationSet struct {
|
||||
MustStashWarning string
|
||||
MustStashTitle string
|
||||
ConfirmationTitle string
|
||||
PressToSubmit string
|
||||
PrevPage string
|
||||
NextPage string
|
||||
GotoTop string
|
||||
@@ -687,6 +686,8 @@ type TranslationSet struct {
|
||||
CreatePullRequestOptions string
|
||||
DefaultBranch string
|
||||
SelectBranch string
|
||||
SelectTargetRemote string
|
||||
NoValidRemoteName string
|
||||
CreatePullRequest string
|
||||
SelectConfigFile string
|
||||
NoConfigFileFoundErr string
|
||||
@@ -1546,7 +1547,6 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
MustStashWarning: "Pulling a patch out into the index requires stashing and unstashing your changes. If something goes wrong, you'll be able to access your files from the stash. Continue?",
|
||||
MustStashTitle: "Must stash",
|
||||
ConfirmationTitle: "Confirmation panel",
|
||||
PressToSubmit: "Press {{.Key}} to submit",
|
||||
PrevPage: "Previous page",
|
||||
NextPage: "Next page",
|
||||
GotoTop: "Scroll to top",
|
||||
@@ -1678,6 +1678,8 @@ func EnglishTranslationSet() *TranslationSet {
|
||||
CreatePullRequestOptions: "View create pull request options",
|
||||
DefaultBranch: "Default branch",
|
||||
SelectBranch: "Select branch",
|
||||
SelectTargetRemote: "Select target remote",
|
||||
NoValidRemoteName: "A remote named '%s' does not exist",
|
||||
SelectConfigFile: "Select config file",
|
||||
NoConfigFileFoundErr: "No config file found",
|
||||
LoadingFileSuggestions: "Loading file suggestions",
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package branch
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var OpenPullRequestInvalidTargetRemoteName = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Open up a pull request, specifying a non-existing target remote",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
// Create an initial commit ('git branch set-upstream-to' bails out otherwise)
|
||||
shell.CreateFileAndAdd("file", "content1")
|
||||
shell.Commit("one")
|
||||
|
||||
// Create a new branch
|
||||
shell.NewBranch("branch-1")
|
||||
|
||||
// Create a couple of remotes
|
||||
shell.CloneIntoRemote("upstream")
|
||||
shell.CloneIntoRemote("origin")
|
||||
|
||||
// To allow a pull request to be created from a branch, it must have an upstream set.
|
||||
shell.SetBranchUpstream("branch-1", "origin/branch-1")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
// Open a PR for the current branch (i.e. 'branch-1')
|
||||
t.Views().
|
||||
Branches().
|
||||
Focus().
|
||||
Press(keys.Branches.ViewPullRequestOptions)
|
||||
|
||||
t.ExpectPopup().
|
||||
Menu().
|
||||
Title(Equals("View create pull request options")).
|
||||
Select(Contains("Select branch")).
|
||||
Confirm()
|
||||
|
||||
// Verify that we're prompted to enter the remote and enter the name of a non-existing one.
|
||||
t.ExpectPopup().
|
||||
Prompt().
|
||||
Title(Equals("Select target remote")).
|
||||
Type("non-existing-remote").
|
||||
Confirm()
|
||||
|
||||
// Verify that this leads to an error being shown (instead of progressing to branch selection).
|
||||
t.ExpectPopup().Alert().
|
||||
Title(Equals("Error")).
|
||||
Content(Contains("A remote named 'non-existing-remote' does not exist")).
|
||||
Confirm()
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,74 @@
|
||||
package branch
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var OpenPullRequestSelectRemoteAndTargetBranch = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Open up a pull request, specifying a remote and target branch",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
config.GetUserConfig().OS.OpenLink = "echo {{link}} > /tmp/openlink"
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
// Create an initial commit ('git branch set-upstream-to' bails out otherwise)
|
||||
shell.CreateFileAndAdd("file", "content1")
|
||||
shell.Commit("one")
|
||||
|
||||
// Create a new branch and a remote that has that branch
|
||||
shell.NewBranch("branch-1")
|
||||
shell.CloneIntoRemote("upstream")
|
||||
|
||||
// Create another branch and a second remote. The first remote doesn't have this branch.
|
||||
shell.NewBranch("branch-2")
|
||||
shell.CloneIntoRemote("origin")
|
||||
|
||||
// To allow a pull request to be created from a branch, it must have an upstream set.
|
||||
shell.SetBranchUpstream("branch-2", "origin/branch-2")
|
||||
|
||||
shell.RunCommand([]string{"git", "remote", "set-url", "origin", "https://github.com/my-personal-fork/lazygit"})
|
||||
shell.RunCommand([]string{"git", "remote", "set-url", "upstream", "https://github.com/jesseduffield/lazygit"})
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
// Open a PR for the current branch (i.e. 'branch-2')
|
||||
t.Views().
|
||||
Branches().
|
||||
Focus().
|
||||
Press(keys.Branches.ViewPullRequestOptions)
|
||||
|
||||
t.ExpectPopup().
|
||||
Menu().
|
||||
Title(Equals("View create pull request options")).
|
||||
Select(Contains("Select branch")).
|
||||
Confirm()
|
||||
|
||||
// Verify that we're prompted to enter the remote
|
||||
t.ExpectPopup().
|
||||
Prompt().
|
||||
Title(Equals("Select target remote")).
|
||||
SuggestionLines(
|
||||
Equals("origin"),
|
||||
Equals("upstream")).
|
||||
ConfirmSuggestion(Equals("upstream"))
|
||||
|
||||
// Verify that we're prompted to enter the target branch and that only those branches
|
||||
// present in the selected remote are listed as suggestions (i.e. 'branch-2' is not there).
|
||||
t.ExpectPopup().
|
||||
Prompt().
|
||||
Title(Equals("branch-2 → upstream/")).
|
||||
SuggestionLines(
|
||||
Equals("branch-1"),
|
||||
Equals("master")).
|
||||
ConfirmSuggestion(Equals("master"))
|
||||
|
||||
// Verify that the expected URL is used (by checking the openlink file)
|
||||
//
|
||||
// Please note that when targeting a different remote - like it's done here in this test -
|
||||
// the link is not yet correct. Thus, this test is expected to fail once this is fixed.
|
||||
t.FileSystem().FileContent(
|
||||
"/tmp/openlink",
|
||||
Equals("https://github.com/my-personal-fork/lazygit/compare/master...branch-2?expand=1\n"))
|
||||
},
|
||||
})
|
||||
@@ -38,7 +38,6 @@ var DropTodoCommitWithUpdateRef = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
).
|
||||
NavigateToLine(Contains("commit 02")).
|
||||
Press(keys.Universal.Edit).
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("pick").Contains("CI commit 07"),
|
||||
Contains("pick").Contains("CI commit 06"),
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package interactive_rebase
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var EditAndAutoAmend = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Edit a commit, make a change and stage it, then continue the rebase to auto-amend the commit",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.
|
||||
CreateNCommits(3)
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("commit 03"),
|
||||
Contains("commit 02"),
|
||||
Contains("commit 01"),
|
||||
).
|
||||
NavigateToLine(Contains("commit 02")).
|
||||
Press(keys.Universal.Edit).
|
||||
Lines(
|
||||
Contains("commit 03"),
|
||||
MatchesRegexp("YOU ARE HERE.*commit 02").IsSelected(),
|
||||
Contains("commit 01"),
|
||||
)
|
||||
|
||||
t.Shell().CreateFile("fixup-file", "fixup content")
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
Press(keys.Files.RefreshFiles).
|
||||
Lines(
|
||||
Contains("??").Contains("fixup-file").IsSelected(),
|
||||
).
|
||||
PressPrimaryAction()
|
||||
|
||||
t.Common().ContinueRebase()
|
||||
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("commit 03"),
|
||||
Contains("commit 02").IsSelected(),
|
||||
Contains("commit 01"),
|
||||
)
|
||||
|
||||
t.Views().Main().
|
||||
Content(Contains("fixup content"))
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,74 @@
|
||||
package interactive_rebase
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var EditLastCommitOfStackedBranch = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Edit and amend the last commit of a branch in a stack of branches, and ensure that it doesn't break the stack",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
GitVersion: AtLeast("2.38.0"),
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
config.GetUserConfig().Git.MainBranches = []string{"master"}
|
||||
config.GetAppState().GitLogShowGraph = "never"
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.
|
||||
CreateNCommits(1).
|
||||
NewBranch("branch1").
|
||||
CreateNCommitsStartingAt(2, 2).
|
||||
NewBranch("branch2").
|
||||
CreateNCommitsStartingAt(2, 4)
|
||||
|
||||
shell.SetConfig("rebase.updateRefs", "true")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("CI commit 05").IsSelected(),
|
||||
Contains("CI commit 04"),
|
||||
Contains("CI * commit 03"),
|
||||
Contains("CI commit 02"),
|
||||
Contains("CI commit 01"),
|
||||
).
|
||||
NavigateToLine(Contains("commit 03")).
|
||||
Press(keys.Universal.Edit).
|
||||
Lines(
|
||||
Contains("pick").Contains("CI commit 05"),
|
||||
Contains("pick").Contains("CI commit 04"),
|
||||
Contains("update-ref").Contains("branch1"),
|
||||
Contains("<-- YOU ARE HERE --- * commit 03").IsSelected(),
|
||||
Contains("CI commit 02"),
|
||||
Contains("CI commit 01"),
|
||||
)
|
||||
|
||||
t.Shell().CreateFile("fixup-file", "fixup content")
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
Press(keys.Files.RefreshFiles).
|
||||
Lines(
|
||||
Contains("??").Contains("fixup-file").IsSelected(),
|
||||
).
|
||||
PressPrimaryAction().
|
||||
Press(keys.Files.AmendLastCommit)
|
||||
t.ExpectPopup().Confirmation().
|
||||
Title(Equals("Amend last commit")).
|
||||
Content(Contains("Are you sure you want to amend last commit?")).
|
||||
Confirm()
|
||||
|
||||
t.Common().ContinueRebase()
|
||||
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("CI commit 05"),
|
||||
Contains("CI commit 04"),
|
||||
Contains("CI * commit 03"),
|
||||
Contains("CI commit 02"),
|
||||
Contains("CI commit 01"),
|
||||
)
|
||||
},
|
||||
})
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package interactive_rebase
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/shared"
|
||||
)
|
||||
|
||||
var EditRangeSelectDownToMergeOutsideRebase = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Select a range of commits (the last one being a merge commit) to edit outside of a rebase",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
GitVersion: AtLeast("2.22.0"), // first version that supports the --rebase-merges option
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shared.CreateMergeCommit(shell)
|
||||
shell.CreateNCommits(2)
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
TopLines(
|
||||
Contains("CI ◯ commit 02").IsSelected(),
|
||||
Contains("CI ◯ commit 01"),
|
||||
Contains("Merge branch 'second-change-branch' into first-change-branch"),
|
||||
).
|
||||
Press(keys.Universal.RangeSelectDown).
|
||||
Press(keys.Universal.RangeSelectDown).
|
||||
Press(keys.Universal.Edit).
|
||||
Lines(
|
||||
Contains("edit CI commit 02").IsSelected(),
|
||||
Contains("edit CI commit 01").IsSelected(),
|
||||
Contains(" CI ⏣─╮ <-- YOU ARE HERE --- Merge branch 'second-change-branch' into first-change-branch").IsSelected(),
|
||||
Contains(" CI │ ◯ * second-change-branch unrelated change"),
|
||||
Contains(" CI │ ◯ second change"),
|
||||
Contains(" CI ◯ │ first change"),
|
||||
Contains(" CI ◯─╯ * original"),
|
||||
Contains(" CI ◯ three"),
|
||||
Contains(" CI ◯ two"),
|
||||
Contains(" CI ◯ one"),
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -48,7 +48,9 @@ var tests = []*components.IntegrationTest{
|
||||
branch.NewBranchAutostash,
|
||||
branch.NewBranchFromRemoteTrackingDifferentName,
|
||||
branch.NewBranchFromRemoteTrackingSameName,
|
||||
branch.OpenPullRequestInvalidTargetRemoteName,
|
||||
branch.OpenPullRequestNoUpstream,
|
||||
branch.OpenPullRequestSelectRemoteAndTargetBranch,
|
||||
branch.OpenWithCliArg,
|
||||
branch.Rebase,
|
||||
branch.RebaseAbortOnConflict,
|
||||
@@ -207,8 +209,11 @@ var tests = []*components.IntegrationTest{
|
||||
interactive_rebase.DropCommitInCopiedBranchWithUpdateRef,
|
||||
interactive_rebase.DropTodoCommitWithUpdateRef,
|
||||
interactive_rebase.DropWithCustomCommentChar,
|
||||
interactive_rebase.EditAndAutoAmend,
|
||||
interactive_rebase.EditFirstCommit,
|
||||
interactive_rebase.EditLastCommitOfStackedBranch,
|
||||
interactive_rebase.EditNonTodoCommitDuringRebase,
|
||||
interactive_rebase.EditRangeSelectDownToMergeOutsideRebase,
|
||||
interactive_rebase.EditRangeSelectOutsideRebase,
|
||||
interactive_rebase.EditTheConflCommit,
|
||||
interactive_rebase.FixupFirstCommit,
|
||||
|
||||
Reference in New Issue
Block a user