1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-04-04 22:34:39 +02:00

Better tag creation UX

Previously we used a single-line prompt for a tag annotation. Now we're using the commit message
prompt.

I've had to update other uses of that prompt to allow the summary and description labels to
be passed in
This commit is contained in:
Jesse Duffield 2023-07-22 14:05:42 +10:00
parent b284970bac
commit 7807b40322
27 changed files with 212 additions and 190 deletions

View File

@ -101,7 +101,7 @@ func localisedTitle(tr *i18n.TranslationSet, str string) string {
"reflogCommits": tr.ReflogCommitsTitle, "reflogCommits": tr.ReflogCommitsTitle,
"tags": tr.TagsTitle, "tags": tr.TagsTitle,
"commitFiles": tr.CommitFilesTitle, "commitFiles": tr.CommitFilesTitle,
"commitMessage": tr.CommitMessageTitle, "commitMessage": tr.CommitSummaryTitle,
"commitDescription": tr.CommitDescriptionTitle, "commitDescription": tr.CommitDescriptionTitle,
"commits": tr.CommitsTitle, "commits": tr.CommitsTitle,
"confirmation": tr.ConfirmationTitle, "confirmation": tr.ConfirmationTitle,

View File

@ -50,13 +50,13 @@ func (self *CommitCommands) ResetToCommit(sha string, strength string, envVars [
Run() Run()
} }
func (self *CommitCommands) CommitCmdObj(message string) oscommands.ICmdObj { func (self *CommitCommands) CommitCmdObj(summary string, description string) oscommands.ICmdObj {
messageArgs := self.commitMessageArgs(message) messageArgs := self.commitMessageArgs(summary, description)
skipHookPrefix := self.UserConfig.Git.SkipHookPrefix skipHookPrefix := self.UserConfig.Git.SkipHookPrefix
cmdArgs := NewGitCmd("commit"). cmdArgs := NewGitCmd("commit").
ArgIf(skipHookPrefix != "" && strings.HasPrefix(message, skipHookPrefix), "--no-verify"). ArgIf(skipHookPrefix != "" && strings.HasPrefix(summary, skipHookPrefix), "--no-verify").
ArgIf(self.signoffFlag() != "", self.signoffFlag()). ArgIf(self.signoffFlag() != "", self.signoffFlag()).
Arg(messageArgs...). Arg(messageArgs...).
ToArgv() ToArgv()
@ -69,8 +69,8 @@ func (self *CommitCommands) RewordLastCommitInEditorCmdObj() oscommands.ICmdObj
} }
// RewordLastCommit rewords the topmost commit with the given message // RewordLastCommit rewords the topmost commit with the given message
func (self *CommitCommands) RewordLastCommit(message string) error { func (self *CommitCommands) RewordLastCommit(summary string, description string) error {
messageArgs := self.commitMessageArgs(message) messageArgs := self.commitMessageArgs(summary, description)
cmdArgs := NewGitCmd("commit"). cmdArgs := NewGitCmd("commit").
Arg("--allow-empty", "--amend", "--only"). Arg("--allow-empty", "--amend", "--only").
@ -80,9 +80,8 @@ func (self *CommitCommands) RewordLastCommit(message string) error {
return self.cmd.New(cmdArgs).Run() return self.cmd.New(cmdArgs).Run()
} }
func (self *CommitCommands) commitMessageArgs(message string) []string { func (self *CommitCommands) commitMessageArgs(summary string, description string) []string {
msg, description, _ := strings.Cut(message, "\n") args := []string{"-m", summary}
args := []string{"-m", msg}
if description != "" { if description != "" {
args = append(args, "-m", description) args = append(args, "-m", description)

View File

@ -10,20 +10,23 @@ import (
func TestCommitRewordCommit(t *testing.T) { func TestCommitRewordCommit(t *testing.T) {
type scenario struct { type scenario struct {
testName string testName string
runner *oscommands.FakeCmdObjRunner runner *oscommands.FakeCmdObjRunner
input string summary string
description string
} }
scenarios := []scenario{ scenarios := []scenario{
{ {
"Single line reword", "Single line reword",
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"commit", "--allow-empty", "--amend", "--only", "-m", "test"}, "", nil), oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"commit", "--allow-empty", "--amend", "--only", "-m", "test"}, "", nil),
"test", "test",
"",
}, },
{ {
"Multi line reword", "Multi line reword",
oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"commit", "--allow-empty", "--amend", "--only", "-m", "test", "-m", "line 2\nline 3"}, "", nil), oscommands.NewFakeRunner(t).ExpectGitArgs([]string{"commit", "--allow-empty", "--amend", "--only", "-m", "test", "-m", "line 2\nline 3"}, "", nil),
"test\nline 2\nline 3", "test",
"line 2\nline 3",
}, },
} }
for _, s := range scenarios { for _, s := range scenarios {
@ -31,7 +34,7 @@ func TestCommitRewordCommit(t *testing.T) {
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
instance := buildCommitCommands(commonDeps{runner: s.runner}) instance := buildCommitCommands(commonDeps{runner: s.runner})
assert.NoError(t, instance.RewordLastCommit(s.input)) assert.NoError(t, instance.RewordLastCommit(s.summary, s.description))
s.runner.CheckForMissingCalls() s.runner.CheckForMissingCalls()
}) })
} }
@ -50,7 +53,8 @@ func TestCommitResetToCommit(t *testing.T) {
func TestCommitCommitCmdObj(t *testing.T) { func TestCommitCommitCmdObj(t *testing.T) {
type scenario struct { type scenario struct {
testName string testName string
message string summary string
description string
configSignoff bool configSignoff bool
configSkipHookPrefix string configSkipHookPrefix string
expectedArgs []string expectedArgs []string
@ -59,35 +63,36 @@ func TestCommitCommitCmdObj(t *testing.T) {
scenarios := []scenario{ scenarios := []scenario{
{ {
testName: "Commit", testName: "Commit",
message: "test", summary: "test",
configSignoff: false, configSignoff: false,
configSkipHookPrefix: "", configSkipHookPrefix: "",
expectedArgs: []string{"commit", "-m", "test"}, expectedArgs: []string{"commit", "-m", "test"},
}, },
{ {
testName: "Commit with --no-verify flag", testName: "Commit with --no-verify flag",
message: "WIP: test", summary: "WIP: test",
configSignoff: false, configSignoff: false,
configSkipHookPrefix: "WIP", configSkipHookPrefix: "WIP",
expectedArgs: []string{"commit", "--no-verify", "-m", "WIP: test"}, expectedArgs: []string{"commit", "--no-verify", "-m", "WIP: test"},
}, },
{ {
testName: "Commit with multiline message", testName: "Commit with multiline message",
message: "line1\nline2", summary: "line1",
description: "line2",
configSignoff: false, configSignoff: false,
configSkipHookPrefix: "", configSkipHookPrefix: "",
expectedArgs: []string{"commit", "-m", "line1", "-m", "line2"}, expectedArgs: []string{"commit", "-m", "line1", "-m", "line2"},
}, },
{ {
testName: "Commit with signoff", testName: "Commit with signoff",
message: "test", summary: "test",
configSignoff: true, configSignoff: true,
configSkipHookPrefix: "", configSkipHookPrefix: "",
expectedArgs: []string{"commit", "--signoff", "-m", "test"}, expectedArgs: []string{"commit", "--signoff", "-m", "test"},
}, },
{ {
testName: "Commit with signoff and no-verify", testName: "Commit with signoff and no-verify",
message: "WIP: test", summary: "WIP: test",
configSignoff: true, configSignoff: true,
configSkipHookPrefix: "WIP", configSkipHookPrefix: "WIP",
expectedArgs: []string{"commit", "--no-verify", "--signoff", "-m", "WIP: test"}, expectedArgs: []string{"commit", "--no-verify", "--signoff", "-m", "WIP: test"},
@ -104,7 +109,7 @@ func TestCommitCommitCmdObj(t *testing.T) {
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expectedArgs, "", nil) runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expectedArgs, "", nil)
instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner}) instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner})
assert.NoError(t, instance.CommitCmdObj(s.message).Run()) assert.NoError(t, instance.CommitCmdObj(s.summary, s.description).Run())
runner.CheckForMissingCalls() runner.CheckForMissingCalls()
}) })
} }

View File

@ -302,7 +302,7 @@ func (self *PatchCommands) PullPatchIntoNewCommit(commits []*models.Commit, comm
head_message, _ := self.commit.GetHeadCommitMessage() head_message, _ := self.commit.GetHeadCommitMessage()
new_message := fmt.Sprintf("Split from \"%s\"", head_message) new_message := fmt.Sprintf("Split from \"%s\"", head_message)
if err := self.commit.CommitCmdObj(new_message).Run(); err != nil { if err := self.commit.CommitCmdObj(new_message, "").Run(); err != nil {
return err return err
} }

View File

@ -35,10 +35,10 @@ func NewRebaseCommands(
} }
} }
func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, message string) error { func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, summary string, description string) error {
if models.IsHeadCommit(commits, index) { if models.IsHeadCommit(commits, index) {
// we've selected the top commit so no rebase is required // we've selected the top commit so no rebase is required
return self.commit.RewordLastCommit(message) return self.commit.RewordLastCommit(summary, description)
} }
err := self.BeginInteractiveRebaseForCommit(commits, index, false) err := self.BeginInteractiveRebaseForCommit(commits, index, false)
@ -47,7 +47,7 @@ func (self *RebaseCommands) RewordCommit(commits []*models.Commit, index int, me
} }
// now the selected commit should be our head so we'll amend it with the new message // now the selected commit should be our head so we'll amend it with the new message
err = self.commit.RewordLastCommit(message) err = self.commit.RewordLastCommit(summary, description)
if err != nil { if err != nil {
return err return err
} }

View File

@ -31,7 +31,7 @@ type CommitMessageViewModel struct {
// the full preserved message (combined summary and description) // the full preserved message (combined summary and description)
preservedMessage string preservedMessage string
// invoked when pressing enter in the commit message panel // invoked when pressing enter in the commit message panel
onConfirm func(string) error onConfirm func(string, string) error
// The message typed in before cycling through history // The message typed in before cycling through history
// We store this separately to 'preservedMessage' because 'preservedMessage' // We store this separately to 'preservedMessage' because 'preservedMessage'
@ -88,15 +88,22 @@ func (self *CommitMessageContext) SetHistoryMessage(message string) {
self.viewModel.historyMessage = message self.viewModel.historyMessage = message
} }
func (self *CommitMessageContext) OnConfirm(message string) error { func (self *CommitMessageContext) OnConfirm(summary string, description string) error {
return self.viewModel.onConfirm(message) return self.viewModel.onConfirm(summary, description)
} }
func (self *CommitMessageContext) SetPanelState(index int, title string, preserveMessage bool, onConfirm func(string) error) { func (self *CommitMessageContext) SetPanelState(
index int,
summaryTitle string,
descriptionTitle string,
preserveMessage bool,
onConfirm func(string, string) error,
) {
self.viewModel.selectedindex = index self.viewModel.selectedindex = index
self.viewModel.preserveMessage = preserveMessage self.viewModel.preserveMessage = preserveMessage
self.viewModel.onConfirm = onConfirm self.viewModel.onConfirm = onConfirm
self.GetView().Title = title self.GetView().Title = summaryTitle
self.c.Views().CommitDescription.Title = descriptionTitle
} }
func (self *CommitMessageContext) RenderCommitLength() { func (self *CommitMessageContext) RenderCommitLength() {

View File

@ -74,7 +74,7 @@ func (gui *Gui) resetHelpersAndControllers() {
Suggestions: suggestionsHelper, Suggestions: suggestionsHelper,
Files: helpers.NewFilesHelper(helperCommon), Files: helpers.NewFilesHelper(helperCommon),
WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, refsHelper, commitsHelper, gpgHelper), WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, refsHelper, commitsHelper, gpgHelper),
Tags: helpers.NewTagsHelper(helperCommon), Tags: helpers.NewTagsHelper(helperCommon, commitsHelper),
GPG: helpers.NewGpgHelper(helperCommon), GPG: helpers.NewGpgHelper(helperCommon),
MergeAndRebase: rebaseHelper, MergeAndRebase: rebaseHelper,
MergeConflicts: mergeConflictsHelper, MergeConflicts: mergeConflictsHelper,

View File

@ -395,7 +395,7 @@ func (self *BranchesController) fastForward(branch *models.Branch) error {
} }
func (self *BranchesController) createTag(branch *models.Branch) error { func (self *BranchesController) createTag(branch *models.Branch) error {
return self.c.Helpers().Tags.CreateTagMenu(branch.FullRefName(), func() {}) return self.c.Helpers().Tags.OpenCreateTagPrompt(branch.FullRefName(), func() {})
} }
func (self *BranchesController) createResetMenu(selectedBranch *models.Branch) error { func (self *BranchesController) createResetMenu(selectedBranch *models.Branch) error {

View File

@ -63,33 +63,44 @@ func (self *CommitsHelper) JoinCommitMessageAndDescription() string {
} }
func (self *CommitsHelper) UpdateCommitPanelView(message string) { func (self *CommitsHelper) UpdateCommitPanelView(message string) {
// first try the passed in message, if not fallback to context -> view in that order
if message != "" { if message != "" {
self.SetMessageAndDescriptionInView(message) self.SetMessageAndDescriptionInView(message)
return return
} }
message = self.c.Contexts().CommitMessage.GetPreservedMessage()
if message != "" { if self.c.Contexts().CommitMessage.GetPreserveMessage() {
self.SetMessageAndDescriptionInView(message) preservedMessage := self.c.Contexts().CommitMessage.GetPreservedMessage()
} else { self.SetMessageAndDescriptionInView(preservedMessage)
self.SetMessageAndDescriptionInView(self.getCommitSummary()) return
} }
self.SetMessageAndDescriptionInView("")
} }
type OpenCommitMessagePanelOpts struct { type OpenCommitMessagePanelOpts struct {
CommitIndex int CommitIndex int
Title string SummaryTitle string
PreserveMessage bool DescriptionTitle string
OnConfirm func(string) error PreserveMessage bool
InitialMessage string OnConfirm func(summary string, description string) error
InitialMessage string
} }
func (self *CommitsHelper) OpenCommitMessagePanel(opts *OpenCommitMessagePanelOpts) error { func (self *CommitsHelper) OpenCommitMessagePanel(opts *OpenCommitMessagePanelOpts) error {
onConfirm := func(summary string, description string) error {
if err := self.CloseCommitMessagePanel(); err != nil {
return err
}
return opts.OnConfirm(summary, description)
}
self.c.Contexts().CommitMessage.SetPanelState( self.c.Contexts().CommitMessage.SetPanelState(
opts.CommitIndex, opts.CommitIndex,
opts.Title, opts.SummaryTitle,
opts.DescriptionTitle,
opts.PreserveMessage, opts.PreserveMessage,
opts.OnConfirm, onConfirm,
) )
self.UpdateCommitPanelView(opts.InitialMessage) self.UpdateCommitPanelView(opts.InitialMessage)
@ -102,17 +113,16 @@ func (self *CommitsHelper) OnCommitSuccess() {
if self.c.Contexts().CommitMessage.GetPreserveMessage() { if self.c.Contexts().CommitMessage.GetPreserveMessage() {
self.c.Contexts().CommitMessage.SetPreservedMessage("") self.c.Contexts().CommitMessage.SetPreservedMessage("")
} }
self.SetMessageAndDescriptionInView("")
} }
func (self *CommitsHelper) HandleCommitConfirm() error { func (self *CommitsHelper) HandleCommitConfirm() error {
fullMessage := self.JoinCommitMessageAndDescription() summary, description := self.getCommitSummary(), self.getCommitDescription()
if fullMessage == "" { if summary == "" {
return self.c.ErrorMsg(self.c.Tr.CommitWithoutMessageErr) return self.c.ErrorMsg(self.c.Tr.CommitWithoutMessageErr)
} }
err := self.c.Contexts().CommitMessage.OnConfirm(fullMessage) err := self.c.Contexts().CommitMessage.OnConfirm(summary, description)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,77 +1,54 @@
package helpers package helpers
import ( import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
) )
// Helper structs are for defining functionality that could be used by multiple contexts.
// For example, here we have a CreateTagMenu which is applicable to both the tags context
// and the commits context.
type TagsHelper struct { type TagsHelper struct {
c *HelperCommon c *HelperCommon
commitsHelper *CommitsHelper
} }
func NewTagsHelper(c *HelperCommon) *TagsHelper { func NewTagsHelper(c *HelperCommon, commitsHelper *CommitsHelper) *TagsHelper {
return &TagsHelper{ return &TagsHelper{
c: c, c: c,
commitsHelper: commitsHelper,
} }
} }
func (self *TagsHelper) CreateTagMenu(ref string, onCreate func()) error { func (self *TagsHelper) OpenCreateTagPrompt(ref string, onCreate func()) error {
return self.c.Menu(types.CreateMenuOptions{ onConfirm := func(tagName string, description string) error {
Title: self.c.Tr.TagMenuTitle, return self.c.WithWaitingStatus(self.c.Tr.CreatingTag, func(gocui.Task) error {
Items: []*types.MenuItem{ if description != "" {
{ self.c.LogAction(self.c.Tr.Actions.CreateAnnotatedTag)
Label: self.c.Tr.LightweightTag, if err := self.c.Git().Tag.CreateAnnotated(tagName, ref, description); err != nil {
OnPress: func() error { return self.c.Error(err)
return self.handleCreateLightweightTag(ref, onCreate) }
}, } else {
}, self.c.LogAction(self.c.Tr.Actions.CreateLightweightTag)
{ if err := self.c.Git().Tag.CreateLightweight(tagName, ref); err != nil {
Label: self.c.Tr.AnnotatedTag, return self.c.Error(err)
OnPress: func() error { }
return self.handleCreateAnnotatedTag(ref, onCreate)
},
},
},
})
}
func (self *TagsHelper) afterTagCreate(onCreate func()) error {
onCreate()
return self.c.Refresh(types.RefreshOptions{
Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS},
})
}
func (self *TagsHelper) handleCreateAnnotatedTag(ref string, onCreate func()) error {
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.TagNameTitle,
HandleConfirm: func(tagName string) error {
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.TagMessageTitle,
HandleConfirm: func(msg string) error {
self.c.LogAction(self.c.Tr.Actions.CreateAnnotatedTag)
if err := self.c.Git().Tag.CreateAnnotated(tagName, ref, msg); err != nil {
return self.c.Error(err)
}
return self.afterTagCreate(onCreate)
},
})
},
})
}
func (self *TagsHelper) handleCreateLightweightTag(ref string, onCreate func()) error {
return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.TagNameTitle,
HandleConfirm: func(tagName string) error {
self.c.LogAction(self.c.Tr.Actions.CreateLightweightTag)
if err := self.c.Git().Tag.CreateLightweight(tagName, ref); err != nil {
return self.c.Error(err)
} }
return self.afterTagCreate(onCreate)
self.commitsHelper.OnCommitSuccess()
return self.c.Refresh(types.RefreshOptions{
Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS},
})
})
}
return self.commitsHelper.OpenCommitMessagePanel(
&OpenCommitMessagePanelOpts{
CommitIndex: context.NoCommitIndex,
InitialMessage: "",
SummaryTitle: self.c.Tr.TagNameTitle,
DescriptionTitle: self.c.Tr.TagMessageTitle,
PreserveMessage: false,
OnConfirm: onConfirm,
}, },
}) )
} }

View File

@ -99,19 +99,19 @@ func (self *WorkingTreeHelper) HandleCommitPressWithMessage(initialMessage strin
return self.commitsHelper.OpenCommitMessagePanel( return self.commitsHelper.OpenCommitMessagePanel(
&OpenCommitMessagePanelOpts{ &OpenCommitMessagePanelOpts{
CommitIndex: context.NoCommitIndex, CommitIndex: context.NoCommitIndex,
InitialMessage: initialMessage, InitialMessage: initialMessage,
Title: self.c.Tr.CommitSummary, SummaryTitle: self.c.Tr.CommitSummaryTitle,
PreserveMessage: true, DescriptionTitle: self.c.Tr.CommitDescriptionTitle,
OnConfirm: self.handleCommit, PreserveMessage: true,
OnConfirm: self.handleCommit,
}, },
) )
} }
func (self *WorkingTreeHelper) handleCommit(message string) error { func (self *WorkingTreeHelper) handleCommit(summary string, description string) error {
cmdObj := self.c.Git().Commit.CommitCmdObj(message) cmdObj := self.c.Git().Commit.CommitCmdObj(summary, description)
self.c.LogAction(self.c.Tr.Actions.Commit) self.c.LogAction(self.c.Tr.Actions.Commit)
_ = self.commitsHelper.PopCommitMessageContexts()
return self.gpgHelper.WithGpgHandling(cmdObj, self.c.Tr.CommittingStatus, func() error { return self.gpgHelper.WithGpgHandling(cmdObj, self.c.Tr.CommittingStatus, func() error {
self.commitsHelper.OnCommitSuccess() self.commitsHelper.OnCommitSuccess()
return nil return nil

View File

@ -267,22 +267,22 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error {
return self.c.Helpers().Commits.OpenCommitMessagePanel( return self.c.Helpers().Commits.OpenCommitMessagePanel(
&helpers.OpenCommitMessagePanelOpts{ &helpers.OpenCommitMessagePanelOpts{
CommitIndex: self.context().GetSelectedLineIdx(), CommitIndex: self.context().GetSelectedLineIdx(),
InitialMessage: commitMessage, InitialMessage: commitMessage,
Title: self.c.Tr.Actions.RewordCommit, SummaryTitle: self.c.Tr.Actions.RewordCommit,
PreserveMessage: false, DescriptionTitle: self.c.Tr.CommitDescriptionTitle,
OnConfirm: self.handleReword, PreserveMessage: false,
OnConfirm: self.handleReword,
}, },
) )
} }
func (self *LocalCommitsController) handleReword(message string) error { func (self *LocalCommitsController) handleReword(summary string, description string) error {
err := self.c.Git().Rebase.RewordCommit(self.c.Model().Commits, self.c.Contexts().LocalCommits.GetSelectedLineIdx(), message) err := self.c.Git().Rebase.RewordCommit(self.c.Model().Commits, self.c.Contexts().LocalCommits.GetSelectedLineIdx(), summary, description)
if err != nil { if err != nil {
return self.c.Error(err) return self.c.Error(err)
} }
self.c.Helpers().Commits.OnCommitSuccess() self.c.Helpers().Commits.OnCommitSuccess()
_ = self.c.Helpers().Commits.PopCommitMessageContexts()
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
} }
@ -682,7 +682,7 @@ func (self *LocalCommitsController) squashAllAboveFixupCommits(commit *models.Co
} }
func (self *LocalCommitsController) createTag(commit *models.Commit) error { func (self *LocalCommitsController) createTag(commit *models.Commit) error {
return self.c.Helpers().Tags.CreateTagMenu(commit.Sha, func() {}) return self.c.Helpers().Tags.OpenCreateTagPrompt(commit.Sha, func() {})
} }
func (self *LocalCommitsController) openSearch() error { func (self *LocalCommitsController) openSearch() error {

View File

@ -141,7 +141,7 @@ func (self *TagsController) createResetMenu(tag *models.Tag) error {
func (self *TagsController) create() error { func (self *TagsController) create() error {
// leaving commit SHA blank so that we're just creating the tag for the current commit // leaving commit SHA blank so that we're just creating the tag for the current commit
return self.c.Helpers().Tags.CreateTagMenu("", func() { self.context().SetSelectedLineIdx(0) }) return self.c.Helpers().Tags.OpenCreateTagPrompt("", func() { self.context().SetSelectedLineIdx(0) })
} }
func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func() error { func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func() error {

View File

@ -181,7 +181,7 @@ func chineseTranslationSet() TranslationSet {
RecentRepos: "最近的仓库", RecentRepos: "最近的仓库",
MergeOptionsTitle: "合并选项", MergeOptionsTitle: "合并选项",
RebaseOptionsTitle: "变基选项", RebaseOptionsTitle: "变基选项",
CommitMessageTitle: "提交讯息", CommitSummaryTitle: "提交讯息",
LocalBranchesTitle: "分支页面", LocalBranchesTitle: "分支页面",
SearchTitle: "搜索", SearchTitle: "搜索",
TagsTitle: "标签页面", TagsTitle: "标签页面",
@ -305,8 +305,8 @@ func chineseTranslationSet() TranslationSet {
EditRemote: "编辑远程仓库", EditRemote: "编辑远程仓库",
TagCommit: "标签提交", TagCommit: "标签提交",
TagMenuTitle: "创建标签", TagMenuTitle: "创建标签",
TagNameTitle: "标签名称", TagNameTitle: "标签名称",
TagMessageTitle: "标签消息", TagMessageTitle: "标签消息",
AnnotatedTag: "附注标签", AnnotatedTag: "附注标签",
LightweightTag: "轻量标签", LightweightTag: "轻量标签",
DeleteTag: "删除标签", DeleteTag: "删除标签",
@ -315,7 +315,6 @@ func chineseTranslationSet() TranslationSet {
PushTagTitle: "将 {{.tagName}} 推送到远程仓库:", PushTagTitle: "将 {{.tagName}} 推送到远程仓库:",
PushTag: "推送标签", PushTag: "推送标签",
CreateTag: "创建标签", CreateTag: "创建标签",
CreateTagTitle: "标签名称:",
FetchRemote: "抓取远程仓库", FetchRemote: "抓取远程仓库",
FetchingRemoteStatus: "抓取远程仓库中", FetchingRemoteStatus: "抓取远程仓库中",
CheckoutCommit: "检出提交", CheckoutCommit: "检出提交",

View File

@ -146,7 +146,7 @@ func dutchTranslationSet() TranslationSet {
RecentRepos: "Recente repositories", RecentRepos: "Recente repositories",
MergeOptionsTitle: "Merge opties", MergeOptionsTitle: "Merge opties",
RebaseOptionsTitle: "Rebase opties", RebaseOptionsTitle: "Rebase opties",
CommitMessageTitle: "Commit bericht", CommitSummaryTitle: "Commit bericht",
LocalBranchesTitle: "Branches", LocalBranchesTitle: "Branches",
SearchTitle: "Zoek", SearchTitle: "Zoek",
TagsTitle: "Tags", TagsTitle: "Tags",
@ -263,14 +263,13 @@ func dutchTranslationSet() TranslationSet {
SetUpstreamMessage: "Weet je zeker dat je de upstream branch van '{{.checkedOut}}' naar '{{.selected}}' wilt zetten", SetUpstreamMessage: "Weet je zeker dat je de upstream branch van '{{.checkedOut}}' naar '{{.selected}}' wilt zetten",
EditRemote: "Wijzig remote", EditRemote: "Wijzig remote",
TagCommit: "Tag commit", TagCommit: "Tag commit",
TagNameTitle: "Tag naam:", TagNameTitle: "Tag naam",
DeleteTag: "Verwijder tag", DeleteTag: "Verwijder tag",
DeleteTagTitle: "Verwijder tag", DeleteTagTitle: "Verwijder tag",
DeleteTagPrompt: "Weet je zeker dat je '{{.tagName}}' wil verwijderen?", DeleteTagPrompt: "Weet je zeker dat je '{{.tagName}}' wil verwijderen?",
PushTagTitle: "Remote om tag '{{.tagName}}' te pushen naar:", PushTagTitle: "Remote om tag '{{.tagName}}' te pushen naar:",
PushTag: "Push tag", PushTag: "Push tag",
CreateTag: "Creëer tag", CreateTag: "Creëer tag",
CreateTagTitle: "Tag naam:",
FetchRemote: "Fetch remote", FetchRemote: "Fetch remote",
FetchingRemoteStatus: "Remote fetchen", FetchingRemoteStatus: "Remote fetchen",
CheckoutCommit: "Checkout commit", CheckoutCommit: "Checkout commit",

View File

@ -192,7 +192,7 @@ type TranslationSet struct {
RecentRepos string RecentRepos string
MergeOptionsTitle string MergeOptionsTitle string
RebaseOptionsTitle string RebaseOptionsTitle string
CommitMessageTitle string CommitSummaryTitle string
CommitDescriptionTitle string CommitDescriptionTitle string
CommitDescriptionSubTitle string CommitDescriptionSubTitle string
LocalBranchesTitle string LocalBranchesTitle string
@ -355,7 +355,7 @@ type TranslationSet struct {
PushTagTitle string PushTagTitle string
PushTag string PushTag string
CreateTag string CreateTag string
CreateTagTitle string CreatingTag string
FetchRemote string FetchRemote string
FetchingRemoteStatus string FetchingRemoteStatus string
CheckoutCommit string CheckoutCommit string
@ -884,7 +884,7 @@ func EnglishTranslationSet() TranslationSet {
RecentRepos: "Recent repositories", RecentRepos: "Recent repositories",
MergeOptionsTitle: "Merge options", MergeOptionsTitle: "Merge options",
RebaseOptionsTitle: "Rebase options", RebaseOptionsTitle: "Rebase options",
CommitMessageTitle: "Commit summary", CommitSummaryTitle: "Commit summary",
CommitDescriptionTitle: "Commit description", CommitDescriptionTitle: "Commit description",
CommitDescriptionSubTitle: "Press {{.togglePanelKeyBinding}} to toggle focus", CommitDescriptionSubTitle: "Press {{.togglePanelKeyBinding}} to toggle focus",
LocalBranchesTitle: "Local branches", LocalBranchesTitle: "Local branches",
@ -1039,8 +1039,8 @@ func EnglishTranslationSet() TranslationSet {
EditRemote: "Edit remote", EditRemote: "Edit remote",
TagCommit: "Tag commit", TagCommit: "Tag commit",
TagMenuTitle: "Create tag", TagMenuTitle: "Create tag",
TagNameTitle: "Tag name:", TagNameTitle: "Tag name",
TagMessageTitle: "Tag message:", TagMessageTitle: "Tag description",
AnnotatedTag: "Annotated tag", AnnotatedTag: "Annotated tag",
LightweightTag: "Lightweight tag", LightweightTag: "Lightweight tag",
DeleteTag: "Delete tag", DeleteTag: "Delete tag",
@ -1049,7 +1049,7 @@ func EnglishTranslationSet() TranslationSet {
PushTagTitle: "Remote to push tag '{{.tagName}}' to:", PushTagTitle: "Remote to push tag '{{.tagName}}' to:",
PushTag: "Push tag", PushTag: "Push tag",
CreateTag: "Create tag", CreateTag: "Create tag",
CreateTagTitle: "Tag name:", CreatingTag: "Creating tag",
FetchRemote: "Fetch remote", FetchRemote: "Fetch remote",
FetchingRemoteStatus: "Fetching remote", FetchingRemoteStatus: "Fetching remote",
CheckoutCommit: "Checkout commit", CheckoutCommit: "Checkout commit",

View File

@ -184,7 +184,7 @@ func japaneseTranslationSet() TranslationSet {
RecentRepos: "最近使用したリポジトリ", RecentRepos: "最近使用したリポジトリ",
// MergeOptionsTitle: "Merge Options", // MergeOptionsTitle: "Merge Options",
// RebaseOptionsTitle: "Rebase Options", // RebaseOptionsTitle: "Rebase Options",
CommitMessageTitle: "コミットメッセージ", CommitSummaryTitle: "コミットメッセージ",
LocalBranchesTitle: "ブランチ", LocalBranchesTitle: "ブランチ",
SearchTitle: "検索", SearchTitle: "検索",
TagsTitle: "タグ", TagsTitle: "タグ",
@ -315,8 +315,8 @@ func japaneseTranslationSet() TranslationSet {
EditRemote: "リモートを編集", EditRemote: "リモートを編集",
TagCommit: "タグを作成", TagCommit: "タグを作成",
TagMenuTitle: "タグを作成", TagMenuTitle: "タグを作成",
TagNameTitle: "タグ名:", TagNameTitle: "タグ名",
TagMessageTitle: "タグメッセージ: ", TagMessageTitle: "タグメッセージ",
AnnotatedTag: "注釈付きタグ", AnnotatedTag: "注釈付きタグ",
LightweightTag: "軽量タグ", LightweightTag: "軽量タグ",
DeleteTag: "タグを削除", DeleteTag: "タグを削除",
@ -325,7 +325,6 @@ func japaneseTranslationSet() TranslationSet {
PushTagTitle: "リモートにタグ '{{.tagName}}' をpush", PushTagTitle: "リモートにタグ '{{.tagName}}' をpush",
PushTag: "タグをpush", PushTag: "タグをpush",
CreateTag: "タグを作成", CreateTag: "タグを作成",
CreateTagTitle: "タグ名:",
FetchRemote: "リモートをfetch", FetchRemote: "リモートをfetch",
FetchingRemoteStatus: "リモートをfetch", FetchingRemoteStatus: "リモートをfetch",
CheckoutCommit: "コミットをチェックアウト", CheckoutCommit: "コミットをチェックアウト",

View File

@ -182,7 +182,7 @@ func koreanTranslationSet() TranslationSet {
RecentRepos: "최근에 사용한 저장소", RecentRepos: "최근에 사용한 저장소",
MergeOptionsTitle: "Merge options", MergeOptionsTitle: "Merge options",
RebaseOptionsTitle: "Rebase options", RebaseOptionsTitle: "Rebase options",
CommitMessageTitle: "커밋메시지", CommitSummaryTitle: "커밋메시지",
LocalBranchesTitle: "브랜치", LocalBranchesTitle: "브랜치",
SearchTitle: "검색", SearchTitle: "검색",
TagsTitle: "태그", TagsTitle: "태그",
@ -310,8 +310,8 @@ func koreanTranslationSet() TranslationSet {
EditRemote: "Remote를 수정", EditRemote: "Remote를 수정",
TagCommit: "Tag commit", TagCommit: "Tag commit",
TagMenuTitle: "태그 작성", TagMenuTitle: "태그 작성",
TagNameTitle: "태그 이름:", TagNameTitle: "태그 이름",
TagMessageTitle: "태그 메시지: ", TagMessageTitle: "태그 메시지",
AnnotatedTag: "Annotated tag", AnnotatedTag: "Annotated tag",
LightweightTag: "Lightweight tag", LightweightTag: "Lightweight tag",
DeleteTag: "태그 삭제", DeleteTag: "태그 삭제",
@ -320,7 +320,6 @@ func koreanTranslationSet() TranslationSet {
PushTagTitle: "원격에 태그 '{{.tagName}}' 를 푸시", PushTagTitle: "원격에 태그 '{{.tagName}}' 를 푸시",
PushTag: "태그를 push", PushTag: "태그를 push",
CreateTag: "태그를 생성", CreateTag: "태그를 생성",
CreateTagTitle: "태그 이름:",
FetchRemote: "원격을 업데이트", FetchRemote: "원격을 업데이트",
FetchingRemoteStatus: "원격을 업데이트 중", FetchingRemoteStatus: "원격을 업데이트 중",
CheckoutCommit: "커밋을 체크아웃", CheckoutCommit: "커밋을 체크아웃",

View File

@ -216,7 +216,7 @@ func RussianTranslationSet() TranslationSet {
RecentRepos: "Последние репозитории", RecentRepos: "Последние репозитории",
MergeOptionsTitle: "Параметры слияния", MergeOptionsTitle: "Параметры слияния",
RebaseOptionsTitle: "Параметры перебазирования", RebaseOptionsTitle: "Параметры перебазирования",
CommitMessageTitle: "Сводка коммита", CommitSummaryTitle: "Сводка коммита",
CommitDescriptionTitle: "Описание коммита", CommitDescriptionTitle: "Описание коммита",
CommitDescriptionSubTitle: "Нажмите вкладку, чтобы переключить фокус", CommitDescriptionSubTitle: "Нажмите вкладку, чтобы переключить фокус",
LocalBranchesTitle: "Локальные Ветки", LocalBranchesTitle: "Локальные Ветки",
@ -371,8 +371,8 @@ func RussianTranslationSet() TranslationSet {
EditRemote: "Редактировать удалённый репозитории", EditRemote: "Редактировать удалённый репозитории",
TagCommit: "Пометить коммит тегом", TagCommit: "Пометить коммит тегом",
TagMenuTitle: "Создать тег", TagMenuTitle: "Создать тег",
TagNameTitle: "Название тега:", TagNameTitle: "Название тега",
TagMessageTitle: "Сообщения тега:", TagMessageTitle: "Сообщения тега",
AnnotatedTag: "Аннотированный тег", AnnotatedTag: "Аннотированный тег",
LightweightTag: "Легковесный тег", LightweightTag: "Легковесный тег",
DeleteTag: "Удалить тег", DeleteTag: "Удалить тег",
@ -381,7 +381,6 @@ func RussianTranslationSet() TranslationSet {
PushTagTitle: "Удалённый репозитории для отправки тега '{{.tagName}}' в:", PushTagTitle: "Удалённый репозитории для отправки тега '{{.tagName}}' в:",
PushTag: "Отправить тег", PushTag: "Отправить тег",
CreateTag: "Создать тег", CreateTag: "Создать тег",
CreateTagTitle: "Название тега:",
FetchRemote: "Получение изменения из удалённого репозитория", FetchRemote: "Получение изменения из удалённого репозитория",
FetchingRemoteStatus: "Получение статуса удалённого репозитория", FetchingRemoteStatus: "Получение статуса удалённого репозитория",
CheckoutCommit: "Переключить коммит", CheckoutCommit: "Переключить коммит",

View File

@ -247,7 +247,7 @@ func traditionalChineseTranslationSet() TranslationSet {
RecentRepos: "最近的版本庫", RecentRepos: "最近的版本庫",
MergeOptionsTitle: "合併選項", MergeOptionsTitle: "合併選項",
RebaseOptionsTitle: "變基選項", RebaseOptionsTitle: "變基選項",
CommitMessageTitle: "提交摘要", CommitSummaryTitle: "提交摘要",
CommitDescriptionTitle: "提交描述", CommitDescriptionTitle: "提交描述",
CommitDescriptionSubTitle: "按 tab 切換焦點", CommitDescriptionSubTitle: "按 tab 切換焦點",
LocalBranchesTitle: "本地分支", LocalBranchesTitle: "本地分支",
@ -398,8 +398,8 @@ func traditionalChineseTranslationSet() TranslationSet {
EditRemote: "編輯遠端", EditRemote: "編輯遠端",
TagCommit: "打標籤到提交", TagCommit: "打標籤到提交",
TagMenuTitle: "建立標籤", TagMenuTitle: "建立標籤",
TagNameTitle: "標籤名稱", TagNameTitle: "標籤名稱",
TagMessageTitle: "標籤訊息", TagMessageTitle: "標籤訊息",
AnnotatedTag: "附註標籤", AnnotatedTag: "附註標籤",
LightweightTag: "輕量標籤", LightweightTag: "輕量標籤",
DeleteTag: "刪除標籤", DeleteTag: "刪除標籤",
@ -408,7 +408,6 @@ func traditionalChineseTranslationSet() TranslationSet {
PushTagTitle: "推送標籤 '{{.tagName}}' 至遠端:", PushTagTitle: "推送標籤 '{{.tagName}}' 至遠端:",
PushTag: "推送標籤", PushTag: "推送標籤",
CreateTag: "建立標籤", CreateTag: "建立標籤",
CreateTagTitle: "標籤名稱:",
FetchRemote: "擷取遠端", FetchRemote: "擷取遠端",
FetchingRemoteStatus: "正在擷取遠端", FetchingRemoteStatus: "正在擷取遠端",
CheckoutCommit: "檢出提交", CheckoutCommit: "檢出提交",

View File

@ -23,3 +23,9 @@ func (self *CommitDescriptionPanelDriver) AddNewline() *CommitDescriptionPanelDr
self.t.press(self.t.keys.Universal.Confirm) self.t.press(self.t.keys.Universal.Confirm)
return self return self
} }
func (self *CommitDescriptionPanelDriver) Title(expected *TextMatcher) *CommitDescriptionPanelDriver {
self.getViewDriver().Title(expected)
return self
}

View File

@ -26,13 +26,8 @@ var CreateTag = NewIntegrationTest(NewIntegrationTestArgs{
SelectNextItem(). SelectNextItem().
Press(keys.Branches.CreateTag) Press(keys.Branches.CreateTag)
t.ExpectPopup().Menu(). t.ExpectPopup().CommitMessagePanel().
Title(Equals("Create tag")). Title(Equals("Tag name")).
Select(Contains("Lightweight")).
Confirm()
t.ExpectPopup().Prompt().
Title(Equals("Tag name:")).
Type("new-tag"). Type("new-tag").
Confirm() Confirm()

View File

@ -23,13 +23,8 @@ var CreateTag = NewIntegrationTest(NewIntegrationTestArgs{
). ).
Press(keys.Commits.CreateTag) Press(keys.Commits.CreateTag)
t.ExpectPopup().Menu(). t.ExpectPopup().CommitMessagePanel().
Title(Equals("Create tag")). Title(Equals("Tag name")).
Select(Contains("Lightweight")).
Confirm()
t.ExpectPopup().Prompt().
Title(Equals("Tag name:")).
Type("new-tag"). Type("new-tag").
Confirm() Confirm()

View File

@ -0,0 +1,37 @@
package tag
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var CreateWhileCommitting = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Draft a commit message, escape out, and make a tag. Verify the draft message doesn't appear in the tag create prompt",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.EmptyCommit("initial commit")
shell.CreateFileAndAdd("file.txt", "file contents")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
Press(keys.Files.CommitChanges).
Tap(func() {
t.ExpectPopup().CommitMessagePanel().
Title(Equals("Commit summary")).
Type("draft message").
Cancel()
})
t.Views().Tags().
Focus().
IsEmpty().
Press(keys.Universal.New).
Tap(func() {
t.ExpectPopup().CommitMessagePanel().
Title(Equals("Tag name")).
InitialText(Equals(""))
})
},
})

View File

@ -19,19 +19,13 @@ var CrudAnnotated = NewIntegrationTest(NewIntegrationTestArgs{
IsEmpty(). IsEmpty().
Press(keys.Universal.New). Press(keys.Universal.New).
Tap(func() { Tap(func() {
t.ExpectPopup().Menu(). t.ExpectPopup().CommitMessagePanel().
Title(Equals("Create tag")). Title(Equals("Tag name")).
Select(Contains("Annotated")).
Confirm()
t.ExpectPopup().Prompt().
Title(Equals("Tag name:")).
Type("new-tag"). Type("new-tag").
Confirm() SwitchToDescription().
Title(Equals("Tag description")).
t.ExpectPopup().Prompt().
Title(Equals("Tag message:")).
Type("message"). Type("message").
SwitchToSummary().
Confirm() Confirm()
}). }).
Lines( Lines(
@ -44,6 +38,13 @@ var CrudAnnotated = NewIntegrationTest(NewIntegrationTestArgs{
Content(Equals("Are you sure you want to delete tag 'new-tag'?")). Content(Equals("Are you sure you want to delete tag 'new-tag'?")).
Confirm() Confirm()
}). }).
IsEmpty() IsEmpty().
Press(keys.Universal.New).
Tap(func() {
// confirm content is cleared on next tag create
t.ExpectPopup().CommitMessagePanel().
Title(Equals("Tag name")).
InitialText(Equals(""))
})
}, },
}) })

View File

@ -19,13 +19,8 @@ var CrudLightweight = NewIntegrationTest(NewIntegrationTestArgs{
IsEmpty(). IsEmpty().
Press(keys.Universal.New). Press(keys.Universal.New).
Tap(func() { Tap(func() {
t.ExpectPopup().Menu(). t.ExpectPopup().CommitMessagePanel().
Title(Equals("Create tag")). Title(Equals("Tag name")).
Select(Contains("Lightweight")).
Confirm()
t.ExpectPopup().Prompt().
Title(Equals("Tag name:")).
Type("new-tag"). Type("new-tag").
Confirm() Confirm()
}). }).

View File

@ -207,6 +207,7 @@ var tests = []*components.IntegrationTest{
sync.PushWithCredentialPrompt, sync.PushWithCredentialPrompt,
sync.RenameBranchAndPull, sync.RenameBranchAndPull,
tag.Checkout, tag.Checkout,
tag.CreateWhileCommitting,
tag.CrudAnnotated, tag.CrudAnnotated,
tag.CrudLightweight, tag.CrudLightweight,
tag.Reset, tag.Reset,