Skip to content

Commit

Permalink
feat: reboot-resistant commit message persistence
Browse files Browse the repository at this point in the history
  • Loading branch information
AzraelSec committed Jan 20, 2025
1 parent 43106b6 commit b845553
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 25 deletions.
40 changes: 34 additions & 6 deletions pkg/gui/context/commit_message_context.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package context

import (
"os"
"path/filepath"
"strconv"
"strings"

"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/spf13/afero"
)

const PreservedCommitMessageFileName = "LAZYGIT_PENDING_COMMIT"

type CommitMessageContext struct {
c *ContextCommon
types.Context
Expand All @@ -33,8 +38,6 @@ type CommitMessageViewModel struct {
// we remember the initial message so that we can tell whether we should preserve
// the message; if it's still identical to the initial message, we don't
initialMessage string
// the full preserved message (combined summary and description)
preservedMessage string
// invoked when pressing enter in the commit message panel
onConfirm func(string, string) error
// invoked when pressing the switch-to-editor key binding
Expand Down Expand Up @@ -75,16 +78,41 @@ func (self *CommitMessageContext) GetSelectedIndex() int {
return self.viewModel.selectedindex
}

func (self *CommitMessageContext) GetPreservedMessagePath() string {
return filepath.Join(self.c.Git().RepoPaths.WorktreeGitDirPath(), PreservedCommitMessageFileName)
}

func (self *CommitMessageContext) GetPreserveMessage() bool {
return self.viewModel.preserveMessage
}

func (self *CommitMessageContext) GetPreservedMessage() string {
return self.viewModel.preservedMessage
func (self *CommitMessageContext) GetPreservedMessage() (string, error) {
buf, err := afero.ReadFile(self.c.Fs, self.GetPreservedMessagePath())
if os.IsNotExist(err) {
return "", nil
}
if err != nil {
return "", err
}
return string(buf), nil
}

func (self *CommitMessageContext) SetPreservedMessage(message string) {
self.viewModel.preservedMessage = message
func (self *CommitMessageContext) SetPreservedMessage(message string) error {
preservedFilePath := self.GetPreservedMessagePath()

_, err := self.c.Fs.Stat(preservedFilePath)
if err != nil && !os.IsNotExist(err) {
return err
}
pendingCommitExists := err == nil || !os.IsNotExist(err)
if !pendingCommitExists && len(message) == 0 {
return nil
}
if pendingCommitExists && len(message) == 0 {
return self.c.Fs.Remove(preservedFilePath)
}

return afero.WriteFile(self.c.Fs, preservedFilePath, []byte(message), 0o644)
}

func (self *CommitMessageContext) GetInitialMessage() string {
Expand Down
3 changes: 1 addition & 2 deletions pkg/gui/controllers/commit_description_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ func (self *CommitDescriptionController) switchToCommitMessage() error {
}

func (self *CommitDescriptionController) close() error {
self.c.Helpers().Commits.CloseCommitMessagePanel()
return nil
return self.c.Helpers().Commits.CloseCommitMessagePanel()
}

func (self *CommitDescriptionController) confirm() error {
Expand Down
3 changes: 1 addition & 2 deletions pkg/gui/controllers/commit_message_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,7 @@ func (self *CommitMessageController) confirm() error {
}

func (self *CommitMessageController) close() error {
self.c.Helpers().Commits.CloseCommitMessagePanel()
return nil
return self.c.Helpers().Commits.CloseCommitMessagePanel()
}

func (self *CommitMessageController) openCommitMenu() error {
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 @@ -207,7 +207,7 @@ func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error {
PreserveMessage: false,
OnConfirm: func(summary string, description string) error {
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
self.c.Helpers().Commits.CloseCommitMessagePanel()
_ = self.c.Helpers().Commits.CloseCommitMessagePanel()
self.c.LogAction(self.c.Tr.Actions.MovePatchIntoNewCommit)
err := self.c.Git().Patch.PullPatchIntoNewCommit(self.c.Model().Commits, commitIndex, summary, description)
if err := self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err); err != nil {
Expand Down
27 changes: 20 additions & 7 deletions pkg/gui/controllers/helpers/commits_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ func (self *CommitsHelper) SwitchToEditor() error {
return err
}

self.CloseCommitMessagePanel()
if err := self.CloseCommitMessagePanel(); err != nil {
return err
}

return self.c.Contexts().CommitMessage.SwitchToEditor(filepath)
}
Expand All @@ -113,7 +115,11 @@ func (self *CommitsHelper) UpdateCommitPanelView(message string) {
}

if self.c.Contexts().CommitMessage.GetPreserveMessage() {
preservedMessage := self.c.Contexts().CommitMessage.GetPreservedMessage()
preservedMessage, err := self.c.Contexts().CommitMessage.GetPreservedMessage()
if err != nil {
self.c.Log.Errorf("error during persisted commit message retrieval: %s", err.Error())
return
}
self.SetMessageAndDescriptionInView(preservedMessage)
return
}
Expand All @@ -133,7 +139,9 @@ type OpenCommitMessagePanelOpts struct {

func (self *CommitsHelper) OpenCommitMessagePanel(opts *OpenCommitMessagePanelOpts) {
onConfirm := func(summary string, description string) error {
self.CloseCommitMessagePanel()
if err := self.CloseCommitMessagePanel(); err != nil {
return err
}

return opts.OnConfirm(summary, description)
}
Expand All @@ -153,11 +161,12 @@ func (self *CommitsHelper) OpenCommitMessagePanel(opts *OpenCommitMessagePanelOp
self.c.Context().Push(self.c.Contexts().CommitMessage)
}

func (self *CommitsHelper) OnCommitSuccess() {
func (self *CommitsHelper) OnCommitSuccess() error {
// if we have a preserved message we want to clear it on success
if self.c.Contexts().CommitMessage.GetPreserveMessage() {
self.c.Contexts().CommitMessage.SetPreservedMessage("")
return self.c.Contexts().CommitMessage.SetPreservedMessage("")
}
return nil
}

func (self *CommitsHelper) HandleCommitConfirm() error {
Expand All @@ -175,11 +184,13 @@ func (self *CommitsHelper) HandleCommitConfirm() error {
return nil
}

func (self *CommitsHelper) CloseCommitMessagePanel() {
func (self *CommitsHelper) CloseCommitMessagePanel() error {
var err error

if self.c.Contexts().CommitMessage.GetPreserveMessage() {
message := self.JoinCommitMessageAndUnwrappedDescription()
if message != self.c.Contexts().CommitMessage.GetInitialMessage() {
self.c.Contexts().CommitMessage.SetPreservedMessage(message)
err = self.c.Contexts().CommitMessage.SetPreservedMessage(message)
}
} else {
self.SetMessageAndDescriptionInView("")
Expand All @@ -191,6 +202,8 @@ func (self *CommitsHelper) CloseCommitMessagePanel() {
self.c.Views().CommitDescription.Visible = false

self.c.Context().Pop()

return err
}

func (self *CommitsHelper) OpenCommitMenu(suggestionFunc func(string) []*types.Suggestion) error {
Expand Down
4 changes: 3 additions & 1 deletion pkg/gui/controllers/helpers/tags_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ func (self *TagsHelper) OpenCreateTagPrompt(ref string, onCreate func()) error {
}
}

self.commitsHelper.OnCommitSuccess()
if err := self.commitsHelper.OnCommitSuccess(); err != nil {
return err
}

return self.c.Refresh(types.RefreshOptions{
Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS},
Expand Down
12 changes: 8 additions & 4 deletions pkg/gui/controllers/helpers/working_tree_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,7 @@ func (self *WorkingTreeHelper) handleCommit(summary string, description string)
cmdObj := self.c.Git().Commit.CommitCmdObj(summary, description)
self.c.LogAction(self.c.Tr.Actions.Commit)
return self.gpgHelper.WithGpgHandling(cmdObj, self.c.Tr.CommittingStatus, func() error {
self.commitsHelper.OnCommitSuccess()
return nil
return self.commitsHelper.OnCommitSuccess()
})
}

Expand All @@ -120,7 +119,9 @@ func (self *WorkingTreeHelper) switchFromCommitMessagePanelToEditor(filepath str
// access to the last message that the user typed, and it might be very
// different from what was last in the commit panel. So the best we can do
// here is to always clear the remembered commit message.
self.commitsHelper.OnCommitSuccess()
if err := self.commitsHelper.OnCommitSuccess(); err != nil {
return err
}

self.c.LogAction(self.c.Tr.Actions.Commit)
return self.c.RunSubprocessAndRefresh(
Expand Down Expand Up @@ -149,7 +150,10 @@ func (self *WorkingTreeHelper) HandleWIPCommitPress() error {
}

func (self *WorkingTreeHelper) HandleCommitPress() error {
message := self.c.Contexts().CommitMessage.GetPreservedMessage()
message, err := self.c.Contexts().CommitMessage.GetPreservedMessage()
if err != nil {
return err
}

if message == "" {
commitPrefixConfig := self.commitPrefixConfigForRepo()
Expand Down
6 changes: 4 additions & 2 deletions pkg/gui/controllers/local_commits_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,11 +418,13 @@ func (self *LocalCommitsController) handleReword(summary string, description str
} else {
err = self.c.Git().Rebase.RewordCommit(self.c.Model().Commits, self.c.Contexts().LocalCommits.GetSelectedLineIdx(), summary, description)
}

if err != nil {
return err
}
self.c.Helpers().Commits.OnCommitSuccess()

if err := self.c.Helpers().Commits.OnCommitSuccess(); err != nil {
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
}

Expand Down

0 comments on commit b845553

Please sign in to comment.