diff --git a/pkg/commands/git_commands/bisect.go b/pkg/commands/git_commands/bisect.go index 101f2037b..6deb32918 100644 --- a/pkg/commands/git_commands/bisect.go +++ b/pkg/commands/git_commands/bisect.go @@ -121,6 +121,15 @@ func (self *BisectCommands) Start() error { return self.cmd.New(cmdArgs).StreamOutput().Run() } +func (self *BisectCommands) StartWithTerms(oldTerm string, newTerm string) error { + cmdArgs := NewGitCmd("bisect").Arg("start"). + Arg("--term-old=" + oldTerm). + Arg("--term-new=" + newTerm). + ToArgv() + + return self.cmd.New(cmdArgs).StreamOutput().Run() +} + // tells us whether we've found our problem commit(s). We return a string slice of // commit sha's if we're done, and that slice may have more that one item if // skipped commits are involved. diff --git a/pkg/gui/controllers/bisect_controller.go b/pkg/gui/controllers/bisect_controller.go index 7c6145912..afa417bb1 100644 --- a/pkg/gui/controllers/bisect_controller.go +++ b/pkg/gui/controllers/bisect_controller.go @@ -153,6 +153,28 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo, }, Key: 'g', }, + { + Label: self.c.Tr.Bisect.ChooseTerms, + OnPress: func() error { + return self.c.Prompt(types.PromptOpts{ + Title: self.c.Tr.Bisect.OldTermPrompt, + HandleConfirm: func(oldTerm string) error { + return self.c.Prompt(types.PromptOpts{ + Title: self.c.Tr.Bisect.NewTermPrompt, + HandleConfirm: func(newTerm string) error { + self.c.LogAction(self.c.Tr.Actions.StartBisect) + if err := self.c.Git().Bisect.StartWithTerms(oldTerm, newTerm); err != nil { + return self.c.Error(err) + } + + return self.c.Helpers().Bisect.PostBisectCommandRefresh() + }, + }) + }, + }) + }, + Key: 't', + }, }, }) } diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 735ac3cf4..2d0fb90e8 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -552,6 +552,9 @@ type Bisect struct { ResetTitle string ResetPrompt string ResetOption string + ChooseTerms string + OldTermPrompt string + NewTermPrompt string BisectMenuTitle string Mark string Skip string @@ -1350,6 +1353,9 @@ func EnglishTranslationSet() TranslationSet { ResetTitle: "Reset 'git bisect'", ResetPrompt: "Are you sure you want to reset 'git bisect'?", ResetOption: "Reset bisect", + ChooseTerms: "Choose bisect terms", + OldTermPrompt: "Term for old/good commit:", + NewTermPrompt: "Term for new/bad commit:", BisectMenuTitle: "Bisect", CompleteTitle: "Bisect complete", CompletePrompt: "Bisect complete! The following commit introduced the change:\n\n%s\n\nDo you want to reset 'git bisect' now?", diff --git a/pkg/integration/tests/bisect/choose_terms.go b/pkg/integration/tests/bisect/choose_terms.go new file mode 100644 index 000000000..825c8f5e2 --- /dev/null +++ b/pkg/integration/tests/bisect/choose_terms.go @@ -0,0 +1,72 @@ +package bisect + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var ChooseTerms = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Start a git bisect by choosing 'broken/fixed' as bisect terms", + ExtraCmdArgs: []string{}, + Skip: false, + SetupRepo: func(shell *Shell) { + shell. + NewBranch("mybranch"). + CreateNCommits(10) + }, + SetupConfig: func(cfg *config.AppConfig) {}, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + markCommitAsFixed := func() { + t.Views().Commits(). + Press(keys.Commits.ViewBisectOptions) + + t.ExpectPopup().Menu().Title(Equals("Bisect")).Select(MatchesRegexp(`Mark .* as fixed`)).Confirm() + } + + markCommitAsBroken := func() { + t.Views().Commits(). + Press(keys.Commits.ViewBisectOptions) + + t.ExpectPopup().Menu().Title(Equals("Bisect")).Select(MatchesRegexp(`Mark .* as broken`)).Confirm() + } + + t.Views().Commits(). + Focus(). + SelectedLine(Contains("CI commit 10")). + Press(keys.Commits.ViewBisectOptions). + Tap(func() { + t.ExpectPopup().Menu().Title(Equals("Bisect")).Select(Contains("Choose bisect terms")).Confirm() + t.ExpectPopup().Prompt().Title(Equals("Term for old/good commit:")).Type("broken").Confirm() + t.ExpectPopup().Prompt().Title(Equals("Term for new/bad commit:")).Type("fixed").Confirm() + }). + NavigateToLine(Contains("CI commit 09")). + Tap(markCommitAsFixed). + SelectedLine(Contains("<-- fixed")). + NavigateToLine(Contains("CI commit 02")). + Tap(markCommitAsBroken). + Lines( + Contains("CI commit 10").DoesNotContain("<--"), + Contains("CI commit 09").Contains("<-- fixed"), + Contains("CI commit 08").DoesNotContain("<--"), + Contains("CI commit 07").DoesNotContain("<--"), + Contains("CI commit 06").DoesNotContain("<--"), + Contains("CI commit 05").Contains("<-- current").IsSelected(), + Contains("CI commit 04").DoesNotContain("<--"), + Contains("CI commit 03").DoesNotContain("<--"), + Contains("CI commit 02").Contains("<-- broken"), + Contains("CI commit 01").DoesNotContain("<--"), + ). + Tap(markCommitAsFixed). + SelectedLine(Contains("CI commit 04").Contains("<-- current")). + Tap(func() { + markCommitAsBroken() + + // commit 5 is the culprit because we marked 4 as broken and 5 as fixed. + t.ExpectPopup().Alert().Title(Equals("Bisect complete")).Content(MatchesRegexp("(?s)commit 05.*Do you want to reset")).Confirm() + }). + IsFocused(). + Content(Contains("CI commit 04")) + + t.Views().Information().Content(DoesNotContain("Bisecting")) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 61a182ffa..17f01995c 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -30,6 +30,7 @@ import ( var tests = []*components.IntegrationTest{ bisect.Basic, + bisect.ChooseTerms, bisect.FromOtherBranch, branch.CheckoutByName, branch.CreateTag,