1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-06-17 00:18:05 +02:00

Better tag creation UX (#2809)

This commit is contained in:
Jesse Duffield
2023-07-22 14:44:18 +10:00
committed by GitHub
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,