Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Commit without pre-commit hooks action is independent on prefix #4374

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions pkg/commands/git_commands/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,11 @@ func (self *CommitCommands) ResetToCommit(hash string, strength string, envVars
Run()
}

func (self *CommitCommands) CommitCmdObj(summary string, description string) oscommands.ICmdObj {
func (self *CommitCommands) CommitCmdObj(summary string, description string, forceSkipHooks bool) oscommands.ICmdObj {
messageArgs := self.commitMessageArgs(summary, description)

skipHookPrefix := self.UserConfig().Git.SkipHookPrefix

cmdArgs := NewGitCmd("commit").
ArgIf(skipHookPrefix != "" && strings.HasPrefix(summary, skipHookPrefix), "--no-verify").
ArgIf(forceSkipHooks || (skipHookPrefix != "" && strings.HasPrefix(summary, skipHookPrefix)), "--no-verify").
ArgIf(self.signoffFlag() != "", self.signoffFlag()).
Arg(messageArgs...).
ToArgv()
Expand All @@ -108,8 +106,9 @@ func (self *CommitCommands) RewordLastCommitInEditorWithMessageFileCmdObj(tmpMes
Arg("--allow-empty", "--amend", "--only", "--edit", "--file="+tmpMessageFile).ToArgv())
}

func (self *CommitCommands) CommitInEditorWithMessageFileCmdObj(tmpMessageFile string) oscommands.ICmdObj {
func (self *CommitCommands) CommitInEditorWithMessageFileCmdObj(tmpMessageFile string, forceSkipHooks bool) oscommands.ICmdObj {
return self.cmd.New(NewGitCmd("commit").
ArgIf(forceSkipHooks, "--no-verify").
Arg("--edit").
Arg("--file="+tmpMessageFile).
ArgIf(self.signoffFlag() != "", self.signoffFlag()).
Expand Down
26 changes: 24 additions & 2 deletions pkg/commands/git_commands/commit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func TestCommitCommitCmdObj(t *testing.T) {
type scenario struct {
testName string
summary string
forceSkipHooks bool
description string
configSignoff bool
configSkipHookPrefix string
Expand All @@ -63,20 +64,39 @@ func TestCommitCommitCmdObj(t *testing.T) {
{
testName: "Commit",
summary: "test",
forceSkipHooks: false,
configSignoff: false,
configSkipHookPrefix: "",
expectedArgs: []string{"commit", "-m", "test"},
},
{
testName: "Commit with --no-verify flag",
testName: "Commit with --no-verify flag < only prefix",
summary: "WIP: test",
forceSkipHooks: false,
configSignoff: false,
configSkipHookPrefix: "WIP",
expectedArgs: []string{"commit", "--no-verify", "-m", "WIP: test"},
},
{
testName: "Commit with --no-verify flag < skip flag and prefix",
summary: "WIP: test",
forceSkipHooks: true,
configSignoff: false,
configSkipHookPrefix: "WIP",
expectedArgs: []string{"commit", "--no-verify", "-m", "WIP: test"},
},
{
testName: "Commit with --no-verify flag < skip flag no prefix",
summary: "test",
forceSkipHooks: true,
configSignoff: false,
configSkipHookPrefix: "WIP",
expectedArgs: []string{"commit", "--no-verify", "-m", "test"},
},
{
testName: "Commit with multiline message",
summary: "line1",
forceSkipHooks: false,
description: "line2",
configSignoff: false,
configSkipHookPrefix: "",
Expand All @@ -85,13 +105,15 @@ func TestCommitCommitCmdObj(t *testing.T) {
{
testName: "Commit with signoff",
summary: "test",
forceSkipHooks: false,
configSignoff: true,
configSkipHookPrefix: "",
expectedArgs: []string{"commit", "--signoff", "-m", "test"},
},
{
testName: "Commit with signoff and no-verify",
summary: "WIP: test",
forceSkipHooks: true,
configSignoff: true,
configSkipHookPrefix: "WIP",
expectedArgs: []string{"commit", "--no-verify", "--signoff", "-m", "WIP: test"},
Expand All @@ -107,7 +129,7 @@ func TestCommitCommitCmdObj(t *testing.T) {
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expectedArgs, "", nil)
instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner})

assert.NoError(t, instance.CommitCmdObj(s.summary, s.description).Run())
assert.NoError(t, instance.CommitCmdObj(s.summary, s.description, s.forceSkipHooks).Run())
runner.CheckForMissingCalls()
})
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/git_commands/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ func (self *PatchCommands) PullPatchIntoNewCommit(
return err
}

if err := self.commit.CommitCmdObj(commitSummary, commitDescription).Run(); err != nil {
if err := self.commit.CommitCmdObj(commitSummary, commitDescription, false).Run(); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a regression; previously it was possible to move a custom patch into a new commit with a WIP prefix and have this skip the hooks; now this is no longer possible. Keeping the prefix logic in CommitCmdObj would fix this.

Note that there are other problems while working with custom patches currently doesn't work well with WIP prefixes; see #3532. But those are unrelated to your PR and can be fixed separately.

return err
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/gui/controllers/custom_patch_options_menu_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error {
SummaryTitle: self.c.Tr.CommitSummaryTitle,
DescriptionTitle: self.c.Tr.CommitDescriptionTitle,
PreserveMessage: false,
OnConfirm: func(summary string, description string) error {
OnConfirm: func(summary string, description string, forceSkipHooks bool) error {
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
self.c.Helpers().Commits.CloseCommitMessagePanel()
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoNewCommit)
Expand Down
13 changes: 9 additions & 4 deletions pkg/gui/controllers/helpers/commits_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,22 @@ type OpenCommitMessagePanelOpts struct {
CommitIndex int
SummaryTitle string
DescriptionTitle string
forceSkipHooks bool
PreserveMessage bool
OnConfirm func(summary string, description string) error
OnSwitchToEditor func(string) error
OnConfirm func(summary string, description string, forceSkipHooks bool) error
OnSwitchToEditor func(string, bool) error
InitialMessage string
}

func (self *CommitsHelper) OpenCommitMessagePanel(opts *OpenCommitMessagePanelOpts) {
onConfirm := func(summary string, description string) error {
self.CloseCommitMessagePanel()

return opts.OnConfirm(summary, description)
return opts.OnConfirm(summary, description, opts.forceSkipHooks)
}

onSwitchToEditor := func(message string) error {
return opts.OnSwitchToEditor(message, opts.forceSkipHooks)
}

self.c.Contexts().CommitMessage.SetPanelState(
Expand All @@ -145,7 +150,7 @@ func (self *CommitsHelper) OpenCommitMessagePanel(opts *OpenCommitMessagePanelOp
opts.PreserveMessage,
opts.InitialMessage,
onConfirm,
opts.OnSwitchToEditor,
onSwitchToEditor,
)

self.UpdateCommitPanelView(opts.InitialMessage)
Expand Down
2 changes: 1 addition & 1 deletion pkg/gui/controllers/helpers/merge_and_rebase_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ func (self *MergeAndRebaseHelper) SquashMergeCommitted(refName, checkedOutBranch
"selectedRef": refName,
"currentBranch": checkedOutBranchName,
})
err = self.c.Git().Commit.CommitCmdObj(message, "").Run()
err = self.c.Git().Commit.CommitCmdObj(message, "", false).Run()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another regression: when setting the squashMergeMessage config to start with the skipHooksPrefix, then we would previously skip the hooks when committing the result of a squash merge. You might argue whether this was intentional, but I do think it makes sense. Again, keeping the prefix logic in CommitCmdObj fixes this.

if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/gui/controllers/helpers/tags_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (self *TagsHelper) OpenCreateTagPrompt(ref string, onCreate func()) error {
})
}

onConfirm := func(tagName string, description string) error {
onConfirm := func(tagName string, description string, forceSkipHooks bool) error {
if self.c.Git().Tag.HasTag(tagName) {
prompt := utils.ResolvePlaceholderString(
self.c.Tr.ForceTagPrompt,
Expand Down Expand Up @@ -72,6 +72,7 @@ func (self *TagsHelper) OpenCreateTagPrompt(ref string, onCreate func()) error {
InitialMessage: "",
SummaryTitle: self.c.Tr.TagNameTitle,
DescriptionTitle: self.c.Tr.TagMessageTitle,
forceSkipHooks: false,
PreserveMessage: false,
OnConfirm: onConfirm,
},
Expand Down
20 changes: 8 additions & 12 deletions pkg/gui/controllers/helpers/working_tree_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,15 @@ func (self *WorkingTreeHelper) OpenMergeTool() error {
return nil
}

func (self *WorkingTreeHelper) HandleCommitPressWithMessage(initialMessage string) error {
func (self *WorkingTreeHelper) HandleCommitPressWithMessage(initialMessage string, forceSkipHooks bool) error {
return self.WithEnsureCommittableFiles(func() error {
self.commitsHelper.OpenCommitMessagePanel(
&OpenCommitMessagePanelOpts{
CommitIndex: context.NoCommitIndex,
InitialMessage: initialMessage,
SummaryTitle: self.c.Tr.CommitSummaryTitle,
DescriptionTitle: self.c.Tr.CommitDescriptionTitle,
forceSkipHooks: forceSkipHooks,
PreserveMessage: true,
OnConfirm: self.handleCommit,
OnSwitchToEditor: self.switchFromCommitMessagePanelToEditor,
Expand All @@ -104,16 +105,16 @@ func (self *WorkingTreeHelper) HandleCommitPressWithMessage(initialMessage strin
})
}

func (self *WorkingTreeHelper) handleCommit(summary string, description string) error {
cmdObj := self.c.Git().Commit.CommitCmdObj(summary, description)
func (self *WorkingTreeHelper) handleCommit(summary string, description string, forceSkipHooks bool) error {
cmdObj := self.c.Git().Commit.CommitCmdObj(summary, description, forceSkipHooks)
self.c.LogAction(self.c.Tr.Actions.Commit)
return self.gpgHelper.WithGpgHandling(cmdObj, self.c.Tr.CommittingStatus, func() error {
self.commitsHelper.OnCommitSuccess()
return nil
})
}

func (self *WorkingTreeHelper) switchFromCommitMessagePanelToEditor(filepath string) error {
func (self *WorkingTreeHelper) switchFromCommitMessagePanelToEditor(filepath string, forceSkipHooks bool) error {
// We won't be able to tell whether the commit was successful, because
// RunSubprocessAndRefresh doesn't return the error (it opens an error alert
// itself and returns nil on error). But even if we could, we wouldn't have
Expand All @@ -124,7 +125,7 @@ func (self *WorkingTreeHelper) switchFromCommitMessagePanelToEditor(filepath str

self.c.LogAction(self.c.Tr.Actions.Commit)
return self.c.RunSubprocessAndRefresh(
self.c.Git().Commit.CommitInEditorWithMessageFileCmdObj(filepath),
self.c.Git().Commit.CommitInEditorWithMessageFileCmdObj(filepath, forceSkipHooks),
)
}

Expand All @@ -140,12 +141,7 @@ func (self *WorkingTreeHelper) HandleCommitEditorPress() error {
}

func (self *WorkingTreeHelper) HandleWIPCommitPress() error {
skipHookPrefix := self.c.UserConfig().Git.SkipHookPrefix
if skipHookPrefix == "" {
return errors.New(self.c.Tr.SkipHookPrefixNotConfigured)
}

return self.HandleCommitPressWithMessage(skipHookPrefix)
return self.HandleCommitPressWithMessage("", true)
}

func (self *WorkingTreeHelper) HandleCommitPress() error {
Expand All @@ -170,7 +166,7 @@ func (self *WorkingTreeHelper) HandleCommitPress() error {
}
}

return self.HandleCommitPressWithMessage(message)
return self.HandleCommitPressWithMessage(message, false)
}

func (self *WorkingTreeHelper) WithEnsureCommittableFiles(handler func() error) error {
Expand Down
6 changes: 3 additions & 3 deletions pkg/gui/controllers/local_commits_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error {
return nil
}

func (self *LocalCommitsController) switchFromCommitMessagePanelToEditor(filepath string) error {
func (self *LocalCommitsController) switchFromCommitMessagePanelToEditor(filepath string, forceSkipHooks bool) error {
if self.isSelectedHeadCommit() {
return self.c.RunSubprocessAndRefresh(
self.c.Git().Commit.RewordLastCommitInEditorWithMessageFileCmdObj(filepath))
Expand All @@ -408,7 +408,7 @@ func (self *LocalCommitsController) switchFromCommitMessagePanelToEditor(filepat
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
}

func (self *LocalCommitsController) handleReword(summary string, description string) error {
func (self *LocalCommitsController) handleReword(summary string, description string, forceSkipHooks bool) error {
if models.IsHeadCommit(self.c.Model().Commits, self.c.Contexts().LocalCommits.GetSelectedLineIdx()) {
// we've selected the top commit so no rebase is required
return self.c.Helpers().GPG.WithGpgHandling(self.c.Git().Commit.RewordLastCommit(summary, description),
Expand Down Expand Up @@ -1026,7 +1026,7 @@ func (self *LocalCommitsController) createAmendCommit(commit *models.Commit, inc
SummaryTitle: self.c.Tr.CreateAmendCommit,
DescriptionTitle: self.c.Tr.CommitDescriptionTitle,
PreserveMessage: false,
OnConfirm: func(summary string, description string) error {
OnConfirm: func(summary string, description string, forceSkipHooks bool) error {
self.c.LogAction(self.c.Tr.Actions.CreateFixupCommit)
return self.c.WithWaitingStatusSync(self.c.Tr.CreatingFixupCommitStatus, func() error {
if err := self.c.Git().Commit.CreateAmendCommit(originalSubject, summary, description, includeFileChanges); err != nil {
Expand Down
4 changes: 4 additions & 0 deletions pkg/integration/components/views.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ func (self *Views) MergeConflicts() *ViewDriver {
return self.regularView("mergeConflicts")
}

func (self *Views) Extras() *ViewDriver {
return self.regularView("extras")
}

func (self *Views) Commits() *ViewDriver {
return self.regularView("commits")
}
Expand Down
47 changes: 47 additions & 0 deletions pkg/integration/tests/commit/commit_skip_hooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package commit

import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)

var fileModHook = `#!/bin/bash

if [[ -f test-wip-commit-prefix ]]; then
echo "Modified text" > test-wip-commit-prefix
fi
`

var CommitSkipHooks = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Commit with skip hook using CommitChangesWithoutHook",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.CreateFile(".git/hooks/pre-commit", fileModHook)
shell.MakeExecutable(".git/hooks/pre-commit")

shell.NewBranch("feature/TEST-002")
shell.CreateFile("test-wip-commit-prefix", "Initial text")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
IsEmpty()

t.Views().Files().
IsFocused().
PressPrimaryAction().
Press(keys.Files.CommitChangesWithoutHook)

t.ExpectPopup().CommitMessagePanel().
Title(Equals("Commit summary")).
Type("foo bar").
Confirm()

t.FileSystem().FileContent("test-wip-commit-prefix", Equals("Initial text"))

t.Views().Commits().Focus()
t.Views().Main().Content(Contains("foo bar"))
t.Views().Extras().Content(Contains("--no-verify"))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting way of checking whether we passed the no-verify flag, but I'm not sure I like it much. If you had a test that committed twice, once with and once without the flag, you couldn't use this check for the second commit.

I'd prefer it if we installed an actual hook (using the technique in fail_hooks_then_commit_no_hooks.go), and have it write something to a file; we can then check whether the file exists (or what it contains) using t.FileSystem().PathPresent() or t.FileSystem().FileContent().

},
})
55 changes: 55 additions & 0 deletions pkg/integration/tests/commit/commit_switch_to_editor_skip_hooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package commit

import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)

var CommitSwitchToEditorSkipHooks = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Commit, then switch from built-in commit message panel to editor",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.CreateFile("file1", "file1 content")
shell.CreateFile("file2", "file2 content")

// Set an editor that appends a line to the existing message. Since
// git adds all this "# Please enter the commit message for your changes"
// stuff, this will result in an extra blank line before the added line.
shell.SetConfig("core.editor", "sh -c 'echo third line >>.git/COMMIT_EDITMSG'")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
IsEmpty()

t.Views().Files().
IsFocused().
PressPrimaryAction(). // stage one of the files
Press(keys.Files.CommitChangesWithoutHook)

t.ExpectPopup().CommitMessagePanel().
Type("first line").
SwitchToDescription().
Type("second line").
SwitchToSummary().
SwitchToEditor()
t.Views().Commits().
Lines(
Contains("first line"),
)

t.Views().Commits().Focus()
t.Views().Main().Content(MatchesRegexp(`first line\n\s*\n\s*second line\n\s*\n\s*third line`))
t.Views().Extras().Content(Contains("--no-verify"))

// Now check that the preserved commit message was cleared:
t.Views().Files().
Focus().
PressPrimaryAction(). // stage the other file
Press(keys.Files.CommitChanges)

t.ExpectPopup().CommitMessagePanel().
InitialText(Equals(""))
},
})
Loading