diff --git a/pkg/commands/git.go b/pkg/commands/git.go index 1c5b31b81..cca406d9a 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -231,14 +231,19 @@ func (c *GitCommand) UpstreamDifferenceCount() (string, string) { return strings.TrimSpace(pushableCount), strings.TrimSpace(pullableCount) } -// GetCommitsToPush Returns the sha's of the commits that have not yet been pushed -// to the remote branch of the current branch -func (c *GitCommand) GetCommitsToPush() []string { - pushables, err := c.OSCommand.RunCommandWithOutput("git rev-list @{u}..head --abbrev-commit") +// getCommitsToPush Returns the sha's of the commits that have not yet been pushed +// to the remote branch of the current branch, a map is returned to ease look up +func (c *GitCommand) getCommitsToPush() map[string]bool { + pushables := map[string]bool{} + o, err := c.OSCommand.RunCommandWithOutput("git rev-list @{u}..head --abbrev-commit") if err != nil { - return []string{} + return pushables } - return utils.SplitLines(pushables) + for _, p := range utils.SplitLines(o) { + pushables[p] = true + } + + return pushables } // RenameCommit renames the topmost commit with the given name @@ -454,26 +459,16 @@ func (c *GitCommand) GetBranchGraph(branchName string) (string, error) { return c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git log --graph --color --abbrev-commit --decorate --date=relative --pretty=medium -100 %s", branchName)) } -func includesString(list []string, a string) bool { - for _, b := range list { - if b == a { - return true - } - } - return false -} - // GetCommits obtains the commits of the current branch func (c *GitCommand) GetCommits() []Commit { - pushables := c.GetCommitsToPush() + pushables := c.getCommitsToPush() log := c.GetLog() commits := []Commit{} // now we can split it up and turn it into commits - lines := utils.SplitLines(log) - for _, line := range lines { + for _, line := range utils.SplitLines(log) { splitLine := strings.Split(line, " ") sha := splitLine[0] - pushed := includesString(pushables, sha) + _, pushed := pushables[sha] commits = append(commits, Commit{ Sha: sha, Name: strings.Join(splitLine[1:], " "), @@ -489,12 +484,12 @@ func (c *GitCommand) GetCommits() []Commit { func (c *GitCommand) GetLog() string { // currently limiting to 30 for performance reasons // TODO: add lazyloading when you scroll down - result, err := c.OSCommand.RunCommandWithOutput("git log --oneline -30") - if err != nil { - // assume if there is an error there are no commits yet for this branch - return "" + if result, err := c.OSCommand.RunCommandWithOutput("git log --oneline -30"); err == nil { + return result } - return result + + // assume if there is an error there are no commits yet for this branch + return "" } // Ignore adds a file to the gitignore for the repo diff --git a/pkg/commands/git_test.go b/pkg/commands/git_test.go index 7a7af0991..aedf5253b 100644 --- a/pkg/commands/git_test.go +++ b/pkg/commands/git_test.go @@ -602,7 +602,7 @@ func TestGitCommandGetCommitsToPush(t *testing.T) { type scenario struct { testName string command func(string, ...string) *exec.Cmd - test func([]string) + test func(map[string]bool) } scenarios := []scenario{ @@ -611,8 +611,8 @@ func TestGitCommandGetCommitsToPush(t *testing.T) { func(string, ...string) *exec.Cmd { return exec.Command("test") }, - func(pushables []string) { - assert.EqualValues(t, []string{}, pushables) + func(pushables map[string]bool) { + assert.EqualValues(t, map[string]bool{}, pushables) }, }, { @@ -620,9 +620,9 @@ func TestGitCommandGetCommitsToPush(t *testing.T) { func(cmd string, args ...string) *exec.Cmd { return exec.Command("echo", "8a2bb0e\n78976bc") }, - func(pushables []string) { + func(pushables map[string]bool) { assert.Len(t, pushables, 2) - assert.EqualValues(t, []string{"8a2bb0e", "78976bc"}, pushables) + assert.EqualValues(t, map[string]bool{"8a2bb0e": true, "78976bc": true}, pushables) }, }, } @@ -631,7 +631,7 @@ func TestGitCommandGetCommitsToPush(t *testing.T) { t.Run(s.testName, func(t *testing.T) { gitCmd := newDummyGitCommand() gitCmd.OSCommand.command = s.command - s.test(gitCmd.GetCommitsToPush()) + s.test(gitCmd.getCommitsToPush()) }) } } @@ -1480,6 +1480,79 @@ func TestGitCommandGetBranchGraph(t *testing.T) { assert.NoError(t, err) } +func TestGitCommandGetCommits(t *testing.T) { + type scenario struct { + testName string + command func(string, ...string) *exec.Cmd + test func([]Commit) + } + + scenarios := []scenario{ + { + "No data found", + func(cmd string, args ...string) *exec.Cmd { + assert.EqualValues(t, "git", cmd) + + switch args[0] { + case "rev-list": + assert.EqualValues(t, []string{"rev-list", "@{u}..head", "--abbrev-commit"}, args) + return exec.Command("echo") + case "log": + assert.EqualValues(t, []string{"log", "--oneline", "-30"}, args) + return exec.Command("echo") + } + + return nil + }, + func(commits []Commit) { + assert.Len(t, commits, 0) + }, + }, + { + "GetCommits returns 2 commits, 1 pushed the other not", + func(cmd string, args ...string) *exec.Cmd { + assert.EqualValues(t, "git", cmd) + + switch args[0] { + case "rev-list": + assert.EqualValues(t, []string{"rev-list", "@{u}..head", "--abbrev-commit"}, args) + return exec.Command("echo", "8a2bb0e") + case "log": + assert.EqualValues(t, []string{"log", "--oneline", "-30"}, args) + return exec.Command("echo", "8a2bb0e commit 1\n78976bc commit 2") + } + + return nil + }, + func(commits []Commit) { + assert.Len(t, commits, 2) + assert.EqualValues(t, []Commit{ + { + Sha: "8a2bb0e", + Name: "commit 1", + Pushed: true, + DisplayString: "8a2bb0e commit 1", + }, + { + Sha: "78976bc", + Name: "commit 2", + Pushed: false, + DisplayString: "78976bc commit 2", + }, + }, commits) + }, + }, + } + + for _, s := range scenarios { + t.Run(s.testName, func(t *testing.T) { + gitCmd := newDummyGitCommand() + gitCmd.OSCommand.command = s.command + s.test(gitCmd.GetCommits()) + }) + } +} + func TestGitCommandDiff(t *testing.T) { gitCommand := newDummyGitCommand() assert.NoError(t, test.GenerateRepo("lots_of_diffs.sh"))