1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-03-05 15:15:49 +02:00

Allow checking for merge conflicts after running a custom command (#2773)

This commit is contained in:
Jesse Duffield 2023-07-13 18:43:25 +10:00 committed by GitHub
commit a251f6ad6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 128 additions and 47 deletions

View File

@ -59,6 +59,12 @@ For a given custom command, here are the allowed fields:
| description | Label for the custom command when displayed in the keybindings menu | no |
| stream | Whether you want to stream the command's output to the Command Log panel | no |
| showOutput | Whether you want to show the command's output in a popup within Lazygit | no |
| after | Actions to take after the command has completed | no |
Here are the options for the `after` key:
| _field_ | _description_ | required |
|-----------------|----------------------|-|
| checkForConflicts | true/false. If true, check for merge conflicts | no |
## Contexts

View File

@ -349,16 +349,21 @@ type OSConfig struct {
OpenLinkCommand string `yaml:"openLinkCommand,omitempty"`
}
type CustomCommandAfterHook struct {
CheckForConflicts bool `yaml:"checkForConflicts"`
}
type CustomCommand struct {
Key string `yaml:"key"`
Context string `yaml:"context"`
Command string `yaml:"command"`
Subprocess bool `yaml:"subprocess"`
Prompts []CustomCommandPrompt `yaml:"prompts"`
LoadingText string `yaml:"loadingText"`
Description string `yaml:"description"`
Stream bool `yaml:"stream"`
ShowOutput bool `yaml:"showOutput"`
Key string `yaml:"key"`
Context string `yaml:"context"`
Command string `yaml:"command"`
Subprocess bool `yaml:"subprocess"`
Prompts []CustomCommandPrompt `yaml:"prompts"`
LoadingText string `yaml:"loadingText"`
Description string `yaml:"description"`
Stream bool `yaml:"stream"`
ShowOutput bool `yaml:"showOutput"`
After CustomCommandAfterHook `yaml:"after"`
}
type CustomCommandPrompt struct {

View File

@ -137,33 +137,47 @@ func (self *MergeAndRebaseHelper) CheckMergeOrRebase(result error) error {
} else if strings.Contains(result.Error(), "No rebase in progress?") {
// assume in this case that we're already done
return nil
} else if isMergeConflictErr(result.Error()) {
mode := self.workingTreeStateNoun()
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.FoundConflictsTitle,
Items: []*types.MenuItem{
{
Label: self.c.Tr.ViewConflictsMenuItem,
OnPress: func() error {
return self.c.PushContext(self.c.Contexts().Files)
},
Key: 'v',
},
{
Label: fmt.Sprintf(self.c.Tr.AbortMenuItem, mode),
OnPress: func() error {
return self.genericMergeCommand(REBASE_OPTION_ABORT)
},
Key: 'a',
},
},
HideCancel: true,
})
} else {
return self.CheckForConflicts(result)
}
}
func (self *MergeAndRebaseHelper) CheckForConflicts(result error) error {
if result == nil {
return nil
}
if isMergeConflictErr(result.Error()) {
return self.PromptForConflictHandling()
} else {
return self.c.ErrorMsg(result.Error())
}
}
func (self *MergeAndRebaseHelper) PromptForConflictHandling() error {
mode := self.workingTreeStateNoun()
return self.c.Menu(types.CreateMenuOptions{
Title: self.c.Tr.FoundConflictsTitle,
Items: []*types.MenuItem{
{
Label: self.c.Tr.ViewConflictsMenuItem,
OnPress: func() error {
return self.c.PushContext(self.c.Contexts().Files)
},
Key: 'v',
},
{
Label: fmt.Sprintf(self.c.Tr.AbortMenuItem, mode),
OnPress: func() error {
return self.genericMergeCommand(REBASE_OPTION_ABORT)
},
Key: 'a',
},
},
HideCancel: true,
})
}
func (self *MergeAndRebaseHelper) AbortMergeOrRebaseWithConfirm() error {
// prompt user to confirm that they want to abort, then do it
mode := self.workingTreeStateNoun()

View File

@ -19,7 +19,12 @@ func NewClient(
helpers *helpers.Helpers,
) *Client {
sessionStateLoader := NewSessionStateLoader(c, helpers.Refs)
handlerCreator := NewHandlerCreator(c, sessionStateLoader, helpers.Suggestions)
handlerCreator := NewHandlerCreator(
c,
sessionStateLoader,
helpers.Suggestions,
helpers.MergeAndRebase,
)
keybindingCreator := NewKeybindingCreator(c)
customCommands := c.UserConfig.CustomCommands

View File

@ -17,27 +17,30 @@ import (
// takes a custom command and returns a function that will be called when the corresponding user-defined keybinding is pressed
type HandlerCreator struct {
c *helpers.HelperCommon
sessionStateLoader *SessionStateLoader
resolver *Resolver
menuGenerator *MenuGenerator
suggestionsHelper *helpers.SuggestionsHelper
c *helpers.HelperCommon
sessionStateLoader *SessionStateLoader
resolver *Resolver
menuGenerator *MenuGenerator
suggestionsHelper *helpers.SuggestionsHelper
mergeAndRebaseHelper *helpers.MergeAndRebaseHelper
}
func NewHandlerCreator(
c *helpers.HelperCommon,
sessionStateLoader *SessionStateLoader,
suggestionsHelper *helpers.SuggestionsHelper,
mergeAndRebaseHelper *helpers.MergeAndRebaseHelper,
) *HandlerCreator {
resolver := NewResolver(c.Common)
menuGenerator := NewMenuGenerator(c.Common)
return &HandlerCreator{
c: c,
sessionStateLoader: sessionStateLoader,
resolver: resolver,
menuGenerator: menuGenerator,
suggestionsHelper: suggestionsHelper,
c: c,
sessionStateLoader: sessionStateLoader,
resolver: resolver,
menuGenerator: menuGenerator,
suggestionsHelper: suggestionsHelper,
mergeAndRebaseHelper: mergeAndRebaseHelper,
}
}
@ -272,7 +275,16 @@ func (self *HandlerCreator) finalHandler(customCommand config.CustomCommand, ses
cmdObj.StreamOutput()
}
output, err := cmdObj.RunWithOutput()
if refreshErr := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil {
self.c.Log.Error(refreshErr)
}
if err != nil {
if customCommand.After.CheckForConflicts {
return self.mergeAndRebaseHelper.CheckForConflicts(err)
}
return self.c.Error(err)
}
@ -280,11 +292,9 @@ func (self *HandlerCreator) finalHandler(customCommand config.CustomCommand, ses
if strings.TrimSpace(output) == "" {
output = self.c.Tr.EmptyOutput
}
if err = self.c.Alert(cmdStr, output); err != nil {
return self.c.Error(err)
}
return self.c.Refresh(types.RefreshOptions{})
return self.c.Alert(cmdStr, output)
}
return self.c.Refresh(types.RefreshOptions{})
return nil
})
}

View File

@ -0,0 +1,40 @@
package custom_commands
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
"github.com/jesseduffield/lazygit/pkg/integration/tests/shared"
)
var CheckForConflicts = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Run a command and check for conflicts after",
ExtraCmdArgs: []string{},
Skip: false,
SetupRepo: func(shell *Shell) {
shared.MergeConflictsSetup(shell)
},
SetupConfig: func(cfg *config.AppConfig) {
cfg.UserConfig.CustomCommands = []config.CustomCommand{
{
Key: "m",
Context: "localBranches",
Command: "git merge {{ .SelectedLocalBranch.Name | quote }}",
After: config.CustomCommandAfterHook{
CheckForConflicts: true,
},
},
}
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Branches().
Focus().
TopLines(
Contains("first-change-branch"),
Contains("second-change-branch"),
).
NavigateToLine(Contains("second-change-branch")).
Press("m")
t.Common().AcknowledgeConflicts()
},
})

View File

@ -75,6 +75,7 @@ var tests = []*components.IntegrationTest{
conflicts.UndoChooseHunk,
custom_commands.BasicCmdAtRuntime,
custom_commands.BasicCmdFromConfig,
custom_commands.CheckForConflicts,
custom_commands.ComplexCmdAtRuntime,
custom_commands.FormPrompts,
custom_commands.MenuFromCommand,