updating specs

This commit is contained in:
Jesse Duffield 2021-12-30 13:11:58 +11:00
parent 1fc0d786ae
commit b028f37ba8
15 changed files with 416 additions and 241 deletions

View file

@ -55,43 +55,6 @@ func NewCommitListBuilder(
}
}
// extractCommitFromLine takes a line from a git log and extracts the sha, message, date, and tag if present
// then puts them into a commit object
// example input:
// 8ad01fe32fcc20f07bc6693f87aa4977c327f1e1|10 hours ago|Jesse Duffield| (HEAD -> master, tag: v0.15.2)|refresh commits when adding a tag
func (self *CommitListBuilder) extractCommitFromLine(line string) *models.Commit {
split := strings.Split(line, SEPARATION_CHAR)
sha := split[0]
unixTimestamp := split[1]
author := split[2]
extraInfo := strings.TrimSpace(split[3])
parentHashes := split[4]
message := strings.Join(split[5:], SEPARATION_CHAR)
tags := []string{}
if extraInfo != "" {
re := regexp.MustCompile(`tag: ([^,\)]+)`)
tagMatch := re.FindStringSubmatch(extraInfo)
if len(tagMatch) > 1 {
tags = append(tags, tagMatch[1])
}
}
unitTimestampInt, _ := strconv.Atoi(unixTimestamp)
return &models.Commit{
Sha: sha,
Name: message,
Tags: tags,
ExtraInfo: extraInfo,
UnixTimestamp: int64(unitTimestampInt),
Author: author,
Parents: strings.Split(parentHashes, " "),
}
}
type GetCommitsOptions struct {
Limit bool
FilterPath string
@ -101,37 +64,6 @@ type GetCommitsOptions struct {
All bool
}
func (self *CommitListBuilder) MergeRebasingCommits(commits []*models.Commit) ([]*models.Commit, error) {
// chances are we have as many commits as last time so we'll set the capacity to be the old length
result := make([]*models.Commit, 0, len(commits))
for i, commit := range commits {
if commit.Status != "rebasing" { // removing the existing rebase commits so we can add the refreshed ones
result = append(result, commits[i:]...)
break
}
}
rebaseMode, err := self.getRebaseMode()
if err != nil {
return nil, err
}
if rebaseMode == "" {
// not in rebase mode so return original commits
return result, nil
}
rebasingCommits, err := self.getHydratedRebasingCommits(rebaseMode)
if err != nil {
return nil, err
}
if len(rebasingCommits) > 0 {
result = append(rebasingCommits, result...)
}
return result, nil
}
// GetCommits obtains the commits of the current branch
func (self *CommitListBuilder) GetCommits(opts GetCommitsOptions) ([]*models.Commit, error) {
commits := []*models.Commit{}
@ -172,7 +104,11 @@ func (self *CommitListBuilder) GetCommits(opts GetCommitsOptions) ([]*models.Com
return nil, err
}
if rebaseMode != "" {
if len(commits) == 0 {
return commits, nil
}
if rebaseMode != REBASE_MODE_NONE {
currentCommit := commits[len(rebasingCommits)]
youAreHere := style.FgYellow.Sprintf("<-- %s ---", self.Tr.YouAreHere)
currentCommit.Name = fmt.Sprintf("%s %s", youAreHere, currentCommit.Name)
@ -186,6 +122,74 @@ func (self *CommitListBuilder) GetCommits(opts GetCommitsOptions) ([]*models.Com
return commits, nil
}
func (self *CommitListBuilder) MergeRebasingCommits(commits []*models.Commit) ([]*models.Commit, error) {
// chances are we have as many commits as last time so we'll set the capacity to be the old length
result := make([]*models.Commit, 0, len(commits))
for i, commit := range commits {
if commit.Status != "rebasing" { // removing the existing rebase commits so we can add the refreshed ones
result = append(result, commits[i:]...)
break
}
}
rebaseMode, err := self.getRebaseMode()
if err != nil {
return nil, err
}
if rebaseMode == REBASE_MODE_NONE {
// not in rebase mode so return original commits
return result, nil
}
rebasingCommits, err := self.getHydratedRebasingCommits(rebaseMode)
if err != nil {
return nil, err
}
if len(rebasingCommits) > 0 {
result = append(rebasingCommits, result...)
}
return result, nil
}
// extractCommitFromLine takes a line from a git log and extracts the sha, message, date, and tag if present
// then puts them into a commit object
// example input:
// 8ad01fe32fcc20f07bc6693f87aa4977c327f1e1|10 hours ago|Jesse Duffield| (HEAD -> master, tag: v0.15.2)|refresh commits when adding a tag
func (self *CommitListBuilder) extractCommitFromLine(line string) *models.Commit {
split := strings.Split(line, SEPARATION_CHAR)
sha := split[0]
unixTimestamp := split[1]
author := split[2]
extraInfo := strings.TrimSpace(split[3])
parentHashes := split[4]
message := strings.Join(split[5:], SEPARATION_CHAR)
tags := []string{}
if extraInfo != "" {
re := regexp.MustCompile(`tag: ([^,\)]+)`)
tagMatch := re.FindStringSubmatch(extraInfo)
if len(tagMatch) > 1 {
tags = append(tags, tagMatch[1])
}
}
unitTimestampInt, _ := strconv.Atoi(unixTimestamp)
return &models.Commit{
Sha: sha,
Name: message,
Tags: tags,
ExtraInfo: extraInfo,
UnixTimestamp: int64(unitTimestampInt),
Author: author,
Parents: strings.Split(parentHashes, " "),
}
}
func (self *CommitListBuilder) getHydratedRebasingCommits(rebaseMode RebaseMode) ([]*models.Commit, error) {
commits, err := self.getRebasingCommits(rebaseMode)
if err != nil {
@ -409,7 +413,7 @@ func (self *CommitListBuilder) getFirstPushedCommit(refName string) (string, err
func (self *CommitListBuilder) getLogCmd(opts GetCommitsOptions) oscommands.ICmdObj {
limitFlag := ""
if opts.Limit {
limitFlag = "-300"
limitFlag = " -300"
}
filterFlag := ""
@ -427,7 +431,7 @@ func (self *CommitListBuilder) getLogCmd(opts GetCommitsOptions) oscommands.ICmd
return self.cmd.New(
fmt.Sprintf(
"git log %s %s %s --oneline %s %s --abbrev=%d %s",
"git log %s %s %s --oneline %s%s --abbrev=%d%s",
self.cmd.Quote(opts.RefName),
orderFlag,
allFlag,
@ -449,5 +453,5 @@ var prettyFormat = fmt.Sprintf(
)
func canExtractCommit(line string) bool {
return strings.Split(line, " ")[0] != "gpg:"
return line != "" && strings.Split(line, " ")[0] != "gpg:"
}

View file

@ -1,11 +1,11 @@
package commands
import (
"os/exec"
"path/filepath"
"testing"
"github.com/jesseduffield/lazygit/pkg/secureexec"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/stretchr/testify/assert"
)
@ -18,7 +18,7 @@ func NewDummyCommitListBuilder() *CommitListBuilder {
Common: cmn,
cmd: nil,
getCurrentBranchName: func() (string, string, error) { return "master", "master", nil },
getRebaseMode: func() (string, error) { return REBASE_MODE_NORMAL, nil },
getRebaseMode: func() (RebaseMode, error) { return REBASE_MODE_NONE, nil },
dotGitDir: ".git",
readFile: func(filename string) ([]byte, error) {
return []byte(""), nil
@ -29,92 +29,184 @@ func NewDummyCommitListBuilder() *CommitListBuilder {
}
}
// TestCommitListBuilderGetMergeBase is a function.
func TestCommitListBuilderGetMergeBase(t *testing.T) {
const commitsOutput = `0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield| (HEAD -> better-tests)|b21997d6b4cbdf84b149|better typing for rebase mode
b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164|1640824515|Jesse Duffield| (origin/better-tests)|e94e8fc5b6fab4cb755f|fix logging
e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c|1640823749|Jesse Duffield||d8084cd558925eb7c9c3|refactor
d8084cd558925eb7c9c38afeed5725c21653ab90|1640821426|Jesse Duffield||65f910ebd85283b5cce9|WIP
65f910ebd85283b5cce9bf67d03d3f1a9ea3813a|1640821275|Jesse Duffield||26c07b1ab33860a1a759|WIP
26c07b1ab33860a1a7591a0638f9925ccf497ffa|1640750752|Jesse Duffield||3d4470a6c072208722e5|WIP
3d4470a6c072208722e5ae9a54bcb9634959a1c5|1640748818|Jesse Duffield||053a66a7be3da43aacdc|WIP
053a66a7be3da43aacdc7aa78e1fe757b82c4dd2|1640739815|Jesse Duffield||985fe482e806b172aea4|refactoring the config struct`
func TestGetCommits(t *testing.T) {
type scenario struct {
testName string
command func(string, ...string) *exec.Cmd
test func(string, error)
testName string
runner oscommands.ICmdObjRunner
expectedCommits []*models.Commit
expectedError error
rebaseMode RebaseMode
currentBranchName string
opts GetCommitsOptions
}
scenarios := []scenario{
{
"swallows an error if the call to merge-base returns an error",
func(cmd string, args ...string) *exec.Cmd {
assert.EqualValues(t, "git", cmd)
testName: "should return no commits if there are none",
rebaseMode: REBASE_MODE_NONE,
currentBranchName: "master",
opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false},
runner: oscommands.NewFakeRunner(t).
Expect(`git merge-base "HEAD" "HEAD"@{u}`, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
Expect(`git log "HEAD" --topo-order --oneline --pretty=format:"%H|%at|%aN|%d|%p|%s" --abbrev=20`, "", nil),
switch args[0] {
case "symbolic-ref":
assert.EqualValues(t, []string{"symbolic-ref", "--short", "HEAD"}, args)
return secureexec.Command("echo", "master")
case "merge-base":
assert.EqualValues(t, []string{"merge-base", "HEAD", "master"}, args)
return secureexec.Command("test")
}
return nil
},
func(output string, err error) {
assert.NoError(t, err)
assert.EqualValues(t, "", output)
},
expectedCommits: []*models.Commit{},
expectedError: nil,
},
{
"returns the commit when master",
func(cmd string, args ...string) *exec.Cmd {
assert.EqualValues(t, "git", cmd)
testName: "should return commits if they are present",
rebaseMode: REBASE_MODE_NONE,
currentBranchName: "master",
opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false},
runner: oscommands.NewFakeRunner(t).
// here it's seeing which commits are yet to be pushed
Expect(`git merge-base "HEAD" "HEAD"@{u}`, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil).
// here it's actually getting all the commits in a formatted form, one per line
Expect(`git log "HEAD" --topo-order --oneline --pretty=format:"%H|%at|%aN|%d|%p|%s" --abbrev=20`, commitsOutput, nil).
// here it's seeing where our branch diverged from the master branch so that we can mark that commit and parent commits as 'merged'
Expect(`git merge-base "HEAD" "master"`, "26c07b1ab33860a1a7591a0638f9925ccf497ffa", nil),
switch args[0] {
case "symbolic-ref":
assert.EqualValues(t, []string{"symbolic-ref", "--short", "HEAD"}, args)
return secureexec.Command("echo", "master")
case "merge-base":
assert.EqualValues(t, []string{"merge-base", "HEAD", "master"}, args)
return secureexec.Command("echo", "blah")
}
return nil
},
func(output string, err error) {
assert.NoError(t, err)
assert.Equal(t, "blah", output)
},
},
{
"checks against develop when a feature branch",
func(cmd string, args ...string) *exec.Cmd {
assert.EqualValues(t, "git", cmd)
switch args[0] {
case "symbolic-ref":
assert.EqualValues(t, []string{"symbolic-ref", "--short", "HEAD"}, args)
return secureexec.Command("echo", "feature/test")
case "merge-base":
assert.EqualValues(t, []string{"merge-base", "HEAD", "develop"}, args)
return secureexec.Command("echo", "blah")
}
return nil
},
func(output string, err error) {
assert.NoError(t, err)
assert.Equal(t, "blah", output)
},
},
{
"bubbles up error if there is one",
func(cmd string, args ...string) *exec.Cmd {
return secureexec.Command("test")
},
func(output string, err error) {
assert.Error(t, err)
assert.Equal(t, "", output)
expectedCommits: []*models.Commit{
{
Sha: "0eea75e8c631fba6b58135697835d58ba4c18dbc",
Name: "better typing for rebase mode",
Status: "unpushed",
Action: "",
Tags: []string{},
ExtraInfo: "(HEAD -> better-tests)",
Author: "Jesse Duffield",
UnixTimestamp: 1640826609,
Parents: []string{
"b21997d6b4cbdf84b149",
},
},
{
Sha: "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164",
Name: "fix logging",
Status: "pushed",
Action: "",
Tags: []string{},
ExtraInfo: "(origin/better-tests)",
Author: "Jesse Duffield",
UnixTimestamp: 1640824515,
Parents: []string{
"e94e8fc5b6fab4cb755f",
},
},
{
Sha: "e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c",
Name: "refactor",
Status: "pushed",
Action: "",
Tags: []string{},
ExtraInfo: "",
Author: "Jesse Duffield",
UnixTimestamp: 1640823749,
Parents: []string{
"d8084cd558925eb7c9c3",
},
},
{
Sha: "d8084cd558925eb7c9c38afeed5725c21653ab90",
Name: "WIP",
Status: "pushed",
Action: "",
Tags: []string{},
ExtraInfo: "",
Author: "Jesse Duffield",
UnixTimestamp: 1640821426,
Parents: []string{
"65f910ebd85283b5cce9",
},
},
{
Sha: "65f910ebd85283b5cce9bf67d03d3f1a9ea3813a",
Name: "WIP",
Status: "pushed",
Action: "",
Tags: []string{},
ExtraInfo: "",
Author: "Jesse Duffield",
UnixTimestamp: 1640821275,
Parents: []string{
"26c07b1ab33860a1a759",
},
},
{
Sha: "26c07b1ab33860a1a7591a0638f9925ccf497ffa",
Name: "WIP",
Status: "merged",
Action: "",
Tags: []string{},
ExtraInfo: "",
Author: "Jesse Duffield",
UnixTimestamp: 1640750752,
Parents: []string{
"3d4470a6c072208722e5",
},
},
{
Sha: "3d4470a6c072208722e5ae9a54bcb9634959a1c5",
Name: "WIP",
Status: "merged",
Action: "",
Tags: []string{},
ExtraInfo: "",
Author: "Jesse Duffield",
UnixTimestamp: 1640748818,
Parents: []string{
"053a66a7be3da43aacdc",
},
},
{
Sha: "053a66a7be3da43aacdc7aa78e1fe757b82c4dd2",
Name: "refactoring the config struct",
Status: "merged",
Action: "",
Tags: []string{},
ExtraInfo: "",
Author: "Jesse Duffield",
UnixTimestamp: 1640739815,
Parents: []string{
"985fe482e806b172aea4",
},
},
},
expectedError: nil,
},
}
for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) {
c := NewDummyCommitListBuilder()
c.OSCommand.SetCommand(s.command)
s.test(c.getMergeBase("HEAD"))
for _, scenario := range scenarios {
t.Run(scenario.testName, func(t *testing.T) {
builder := &CommitListBuilder{
Common: utils.NewDummyCommon(),
cmd: oscommands.NewCmdObjBuilderDummy(scenario.runner),
getCurrentBranchName: func() (string, string, error) {
return scenario.currentBranchName, scenario.currentBranchName, nil
},
getRebaseMode: func() (RebaseMode, error) { return scenario.rebaseMode, nil },
dotGitDir: ".git",
readFile: func(filename string) ([]byte, error) {
return []byte(""), nil
},
walkFiles: func(root string, fn filepath.WalkFunc) error {
return nil
},
}
commits, err := builder.GetCommits(scenario.opts)
assert.Equal(t, scenario.expectedCommits, commits)
assert.Equal(t, scenario.expectedError, err)
})
}
}

View file

@ -8,6 +8,9 @@ import (
// command line.
type ICmdObj interface {
GetCmd() *exec.Cmd
// outputs string representation of command. Note that if the command was built
// using NewFromArgs, the output won't be quite the same as what you would type
// into a terminal e.g. 'sh -c git commit' as opposed to 'sh -c "git commit"'
ToString() string
AddEnvVars(...string) ICmdObj
GetEnvVars() []string

View file

@ -19,9 +19,6 @@ type ICmdObjBuilder interface {
Quote(str string) string
}
// poor man's version of explicitly saying that struct X implements interface Y
var _ ICmdObjBuilder = &CmdObjBuilder{}
type CmdObjBuilder struct {
runner ICmdObjRunner
logCmdObj func(ICmdObj)
@ -31,6 +28,9 @@ type CmdObjBuilder struct {
platform *Platform
}
// poor man's version of explicitly saying that struct X implements interface Y
var _ ICmdObjBuilder = &CmdObjBuilder{}
func (self *CmdObjBuilder) New(cmdStr string) ICmdObj {
args := str.ToArgv(cmdStr)
cmd := self.command(args[0], args[1:]...)

View file

@ -14,19 +14,19 @@ type ICmdObjRunner interface {
RunAndProcessLines(cmdObj ICmdObj, onLine func(line string) (bool, error)) error
}
type RunExpectation func(ICmdObj) (string, error)
type Runner struct {
type cmdObjRunner struct {
log *logrus.Entry
logCmdObj func(ICmdObj)
}
func (self *Runner) Run(cmdObj ICmdObj) error {
var _ ICmdObjRunner = &cmdObjRunner{}
func (self *cmdObjRunner) Run(cmdObj ICmdObj) error {
_, err := self.RunWithOutput(cmdObj)
return err
}
func (self *Runner) RunWithOutput(cmdObj ICmdObj) (string, error) {
func (self *cmdObjRunner) RunWithOutput(cmdObj ICmdObj) (string, error) {
self.logCmdObj(cmdObj)
output, err := sanitisedCommandOutput(cmdObj.GetCmd().CombinedOutput())
if err != nil {
@ -35,7 +35,7 @@ func (self *Runner) RunWithOutput(cmdObj ICmdObj) (string, error) {
return output, err
}
func (self *Runner) RunAndProcessLines(cmdObj ICmdObj, onLine func(line string) (bool, error)) error {
func (self *cmdObjRunner) RunAndProcessLines(cmdObj ICmdObj, onLine func(line string) (bool, error)) error {
cmd := cmdObj.GetCmd()
stdoutPipe, err := cmd.StdoutPipe()
if err != nil {

View file

@ -1,6 +1,7 @@
package oscommands
import (
"github.com/jesseduffield/lazygit/pkg/secureexec"
"github.com/jesseduffield/lazygit/pkg/utils"
)
@ -8,3 +9,18 @@ import (
func NewDummyOSCommand() *OSCommand {
return NewOSCommand(utils.NewDummyCommon())
}
func NewCmdObjBuilderDummy(runner ICmdObjRunner) ICmdObjBuilder {
return &CmdObjBuilder{
runner: runner,
logCmdObj: func(ICmdObj) {},
command: secureexec.Command,
platform: &Platform{
OS: "darwin",
Shell: "bash",
ShellArg: "-c",
OpenCommand: "open {{filename}}",
OpenLinkCommand: "open {{link}}",
},
}
}

View file

@ -0,0 +1,82 @@
package oscommands
import (
"bufio"
"fmt"
"strings"
"testing"
"github.com/go-errors/errors"
"github.com/stretchr/testify/assert"
)
type FakeCmdObjRunner struct {
t *testing.T
expectedCmds []func(ICmdObj) (string, error)
expectedCmdIndex int
}
var _ ICmdObjRunner = &FakeCmdObjRunner{}
func NewFakeRunner(t *testing.T) *FakeCmdObjRunner {
return &FakeCmdObjRunner{t: t}
}
func (self *FakeCmdObjRunner) Run(cmdObj ICmdObj) error {
_, err := self.RunWithOutput(cmdObj)
return err
}
func (self *FakeCmdObjRunner) RunWithOutput(cmdObj ICmdObj) (string, error) {
if self.expectedCmdIndex > len(self.expectedCmds)-1 {
self.t.Errorf("ran too many commands. Unexpected command: `%s`", cmdObj.ToString())
return "", errors.New("ran too many commands")
}
expectedCmd := self.expectedCmds[self.expectedCmdIndex]
self.expectedCmdIndex++
return expectedCmd(cmdObj)
}
func (self *FakeCmdObjRunner) RunAndProcessLines(cmdObj ICmdObj, onLine func(line string) (bool, error)) error {
output, err := self.RunWithOutput(cmdObj)
if err != nil {
return err
}
scanner := bufio.NewScanner(strings.NewReader(output))
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
line := scanner.Text()
stop, err := onLine(line)
if err != nil {
return err
}
if stop {
break
}
}
return nil
}
func (self *FakeCmdObjRunner) ExpectFunc(fn func(cmdObj ICmdObj) (string, error)) *FakeCmdObjRunner {
self.expectedCmds = append(self.expectedCmds, fn)
return self
}
func (self *FakeCmdObjRunner) Expect(expectedCmdStr string, output string, err error) *FakeCmdObjRunner {
self.ExpectFunc(func(cmdObj ICmdObj) (string, error) {
cmdStr := cmdObj.ToString()
if cmdStr != expectedCmdStr {
assert.Equal(self.t, expectedCmdStr, cmdStr, fmt.Sprintf("expected command %d to be %s, but was %s", self.expectedCmdIndex+1, expectedCmdStr, cmdStr))
return "", errors.New("expected cmd")
}
return output, err
})
return self
}

View file

@ -17,27 +17,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils"
)
// Platform stores the os state
type Platform struct {
OS string
Shell string
ShellArg string
OpenCommand string
OpenLinkCommand string
}
type ICommander interface {
Run(ICmdObj) error
RunWithOutput(ICmdObj) (string, error)
}
type RealCommander struct {
}
func (self *RealCommander) Run(cmdObj ICmdObj) error {
return cmdObj.GetCmd().Run()
}
// OSCommand holds all the os commands
type OSCommand struct {
*common.Common
@ -56,6 +35,15 @@ type OSCommand struct {
Cmd *CmdObjBuilder
}
// Platform stores the os state
type Platform struct {
OS string
Shell string
ShellArg string
OpenCommand string
OpenLinkCommand string
}
// TODO: make these fields private
type CmdLogEntry struct {
// e.g. 'git commit -m "haha"'
@ -99,7 +87,7 @@ func NewOSCommand(common *common.Common) *OSCommand {
removeFile: os.RemoveAll,
}
runner := &Runner{log: common.Log, logCmdObj: c.LogCmdObj}
runner := &cmdObjRunner{log: common.Log, logCmdObj: c.LogCmdObj}
c.Cmd = &CmdObjBuilder{runner: runner, command: command, logCmdObj: c.LogCmdObj, platform: platform}
return c
@ -117,7 +105,7 @@ func (c *OSCommand) WithSpan(span string) *OSCommand {
*newOSCommand = *c
newOSCommand.CmdLogSpan = span
newOSCommand.Cmd.logCmdObj = newOSCommand.LogCmdObj
newOSCommand.Cmd.runner = &Runner{log: c.Log, logCmdObj: newOSCommand.LogCmdObj}
newOSCommand.Cmd.runner = &cmdObjRunner{log: c.Log, logCmdObj: newOSCommand.LogCmdObj}
return newOSCommand
}

View file

@ -2,10 +2,8 @@ package commands
import (
"os/exec"
"regexp"
"testing"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/test"
"github.com/stretchr/testify/assert"
)
@ -58,40 +56,40 @@ func TestGitCommandRebaseBranch(t *testing.T) {
}
}
// TestGitCommandSkipEditorCommand confirms that SkipEditorCommand injects
// environment variables that suppress an interactive editor
func TestGitCommandSkipEditorCommand(t *testing.T) {
cmd := NewDummyGitCommand()
// // TestGitCommandSkipEditorCommand confirms that SkipEditorCommand injects
// // environment variables that suppress an interactive editor
// func TestGitCommandSkipEditorCommand(t *testing.T) {
// cmd := NewDummyGitCommand()
cmd.OSCommand.SetBeforeExecuteCmd(func(cmdObj oscommands.ICmdObj) {
test.AssertContainsMatch(
t,
cmdObj.GetEnvVars(),
regexp.MustCompile("^VISUAL="),
"expected VISUAL to be set for a non-interactive external command",
)
// cmd.OSCommand.SetBeforeExecuteCmd(func(cmdObj oscommands.ICmdObj) {
// test.AssertContainsMatch(
// t,
// cmdObj.GetEnvVars(),
// regexp.MustCompile("^VISUAL="),
// "expected VISUAL to be set for a non-interactive external command",
// )
test.AssertContainsMatch(
t,
cmdObj.GetEnvVars(),
regexp.MustCompile("^EDITOR="),
"expected EDITOR to be set for a non-interactive external command",
)
// test.AssertContainsMatch(
// t,
// cmdObj.GetEnvVars(),
// regexp.MustCompile("^EDITOR="),
// "expected EDITOR to be set for a non-interactive external command",
// )
test.AssertContainsMatch(
t,
cmdObj.GetEnvVars(),
regexp.MustCompile("^GIT_EDITOR="),
"expected GIT_EDITOR to be set for a non-interactive external command",
)
// test.AssertContainsMatch(
// t,
// cmdObj.GetEnvVars(),
// regexp.MustCompile("^GIT_EDITOR="),
// "expected GIT_EDITOR to be set for a non-interactive external command",
// )
test.AssertContainsMatch(
t,
cmdObj.GetEnvVars(),
regexp.MustCompile("^LAZYGIT_CLIENT_COMMAND=EXIT_IMMEDIATELY$"),
"expected LAZYGIT_CLIENT_COMMAND to be set for a non-interactive external command",
)
})
// test.AssertContainsMatch(
// t,
// cmdObj.GetEnvVars(),
// regexp.MustCompile("^LAZYGIT_CLIENT_COMMAND=EXIT_IMMEDIATELY$"),
// "expected LAZYGIT_CLIENT_COMMAND to be set for a non-interactive external command",
// )
// })
_ = cmd.runSkipEditorCommand("true")
}
// _ = cmd.runSkipEditorCommand("true")
// }

View file

@ -6,13 +6,17 @@ import (
gogit "github.com/jesseduffield/go-git/v5"
)
type RebaseMode string
type RebaseMode int
const (
REBASE_MODE_NORMAL RebaseMode = "normal"
REBASE_MODE_INTERACTIVE = "interactive"
REBASE_MODE_REBASING = "rebasing"
REBASE_MODE_MERGING = "merging"
// this means we're neither rebasing nor merging
REBASE_MODE_NONE RebaseMode = iota
// this means normal rebase as opposed to interactive rebase
REBASE_MODE_NORMAL
REBASE_MODE_INTERACTIVE
// REBASE_MODE_REBASING is a general state that captures both REBASE_MODE_NORMAL and REBASE_MODE_INTERACTIVE
REBASE_MODE_REBASING
REBASE_MODE_MERGING
)
// RebaseMode returns "" for non-rebase mode, "normal" for normal rebase
@ -20,7 +24,7 @@ const (
func (c *GitCommand) RebaseMode() (RebaseMode, error) {
exists, err := c.OSCommand.FileExists(filepath.Join(c.DotGitDir, "rebase-apply"))
if err != nil {
return "", err
return REBASE_MODE_NONE, err
}
if exists {
return REBASE_MODE_NORMAL, nil
@ -29,20 +33,20 @@ func (c *GitCommand) RebaseMode() (RebaseMode, error) {
if exists {
return REBASE_MODE_INTERACTIVE, err
} else {
return "", err
return REBASE_MODE_NONE, err
}
}
func (c *GitCommand) WorkingTreeState() RebaseMode {
rebaseMode, _ := c.RebaseMode()
if rebaseMode != "" {
if rebaseMode != REBASE_MODE_NONE {
return REBASE_MODE_REBASING
}
merging, _ := c.IsInMergeState()
if merging {
return REBASE_MODE_MERGING
}
return REBASE_MODE_NORMAL
return REBASE_MODE_NONE
}
// IsInMergeState states whether we are still mid-merge

View file

@ -262,7 +262,7 @@ func (gui *Gui) handleCompleteMerge() error {
}
// if we got conflicts after unstashing, we don't want to call any git
// commands to continue rebasing/merging here
if gui.GitCommand.WorkingTreeState() == commands.REBASE_MODE_NORMAL {
if gui.GitCommand.WorkingTreeState() == commands.REBASE_MODE_NONE {
return gui.handleEscapeMerge()
}
// if there are no more files with merge conflicts, we should ask whether the user wants to continue

View file

@ -61,7 +61,7 @@ func (gui *Gui) modeStatuses() []modeStatus {
},
{
isActive: func() bool {
return gui.GitCommand.WorkingTreeState() != commands.REBASE_MODE_NORMAL
return gui.GitCommand.WorkingTreeState() != commands.REBASE_MODE_NONE
},
description: func() string {
workingTreeState := gui.GitCommand.WorkingTreeState()

View file

@ -26,7 +26,7 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error {
},
}
if gui.GitCommand.PatchManager.CanRebase && gui.workingTreeState() == commands.REBASE_MODE_NORMAL {
if gui.GitCommand.PatchManager.CanRebase && gui.GitCommand.WorkingTreeState() == commands.REBASE_MODE_NONE {
menuItems = append(menuItems, []*menuItem{
{
displayString: fmt.Sprintf("remove patch from original commit (%s)", gui.GitCommand.PatchManager.To),
@ -74,7 +74,7 @@ func (gui *Gui) getPatchCommitIndex() int {
}
func (gui *Gui) validateNormalWorkingTreeState() (bool, error) {
if gui.GitCommand.WorkingTreeState() != commands.REBASE_MODE_NORMAL {
if gui.GitCommand.WorkingTreeState() != commands.REBASE_MODE_NONE {
return false, gui.createErrorPanel(gui.Tr.CantPatchWhileRebasingError)
}
return true, nil

View file

@ -144,7 +144,7 @@ func (gui *Gui) abortMergeOrRebaseWithConfirm() error {
func (gui *Gui) workingTreeStateNoun() string {
workingTreeState := gui.GitCommand.WorkingTreeState()
switch workingTreeState {
case commands.REBASE_MODE_NORMAL:
case commands.REBASE_MODE_NONE:
return ""
case commands.REBASE_MODE_MERGING:
return "merge"

View file

@ -28,7 +28,7 @@ func (gui *Gui) refreshStatus() {
status += presentation.ColoredBranchStatus(currentBranch) + " "
}
if gui.GitCommand.WorkingTreeState() != commands.REBASE_MODE_NORMAL {
if gui.GitCommand.WorkingTreeState() != commands.REBASE_MODE_NONE {
status += style.FgYellow.Sprintf("(%s) ", gui.GitCommand.WorkingTreeState())
}
@ -156,15 +156,3 @@ func lazygitTitle() string {
__/ | __/ |
|___/ |___/ `
}
func (gui *Gui) workingTreeState() commands.RebaseMode {
rebaseMode, _ := gui.GitCommand.RebaseMode()
if rebaseMode != "" {
return commands.REBASE_MODE_REBASING
}
merging, _ := gui.GitCommand.IsInMergeState()
if merging {
return commands.REBASE_MODE_MERGING
}
return commands.REBASE_MODE_NORMAL
}