mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-02-21 19:48:58 +02:00
Merge pull request #12 from jesseduffield/master
Update to latest master
This commit is contained in:
commit
c64fb87b2b
5
main.go
5
main.go
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -40,13 +41,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
appConfig, err := config.NewAppConfig("lazygit", version, commit, date, buildSource, debuggingFlag)
|
appConfig, err := config.NewAppConfig("lazygit", version, commit, date, buildSource, debuggingFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
app, err := app.Setup(appConfig)
|
app, err := app.Setup(appConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.Log.Error(err.Error())
|
app.Log.Error(err.Error())
|
||||||
panic(err)
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Gui.RunWithSubprocesses()
|
app.Gui.RunWithSubprocesses()
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/i18n"
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -59,11 +58,13 @@ func setupRepositoryAndWorktree(openGitRepository func(string) (*gogit.Repositor
|
|||||||
|
|
||||||
// GitCommand is our main git interface
|
// GitCommand is our main git interface
|
||||||
type GitCommand struct {
|
type GitCommand struct {
|
||||||
Log *logrus.Entry
|
Log *logrus.Entry
|
||||||
OSCommand *OSCommand
|
OSCommand *OSCommand
|
||||||
Worktree *gogit.Worktree
|
Worktree *gogit.Worktree
|
||||||
Repo *gogit.Repository
|
Repo *gogit.Repository
|
||||||
Tr *i18n.Localizer
|
Tr *i18n.Localizer
|
||||||
|
getGlobalGitConfig func(string) (string, error)
|
||||||
|
getLocalGitConfig func(string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGitCommand it runs git commands
|
// NewGitCommand it runs git commands
|
||||||
@ -92,11 +93,13 @@ func NewGitCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.Localizer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &GitCommand{
|
return &GitCommand{
|
||||||
Log: log,
|
Log: log,
|
||||||
OSCommand: osCommand,
|
OSCommand: osCommand,
|
||||||
Tr: tr,
|
Tr: tr,
|
||||||
Worktree: worktree,
|
Worktree: worktree,
|
||||||
Repo: repo,
|
Repo: repo,
|
||||||
|
getGlobalGitConfig: gitconfig.Global,
|
||||||
|
getLocalGitConfig: gitconfig.Local,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,28 +173,37 @@ func (c *GitCommand) MergeStatusFiles(oldFiles, newFiles []File) []File {
|
|||||||
return newFiles
|
return newFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
headResults := []File{}
|
appendedIndexes := []int{}
|
||||||
tailResults := []File{}
|
|
||||||
|
|
||||||
for _, newFile := range newFiles {
|
// retain position of files we already could see
|
||||||
var isHeadResult bool
|
result := []File{}
|
||||||
|
for _, oldFile := range oldFiles {
|
||||||
for _, oldFile := range oldFiles {
|
for newIndex, newFile := range newFiles {
|
||||||
if oldFile.Name == newFile.Name {
|
if oldFile.Name == newFile.Name {
|
||||||
isHeadResult = true
|
result = append(result, newFile)
|
||||||
|
appendedIndexes = append(appendedIndexes, newIndex)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if isHeadResult {
|
|
||||||
headResults = append(headResults, newFile)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
tailResults = append(tailResults, newFile)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return append(headResults, tailResults...)
|
// append any new files to the end
|
||||||
|
for index, newFile := range newFiles {
|
||||||
|
if !includesInt(appendedIndexes, index) {
|
||||||
|
result = append(result, newFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func includesInt(list []int, a int) bool {
|
||||||
|
for _, b := range list {
|
||||||
|
if b == a {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBranchName branch name
|
// GetBranchName branch name
|
||||||
@ -274,89 +286,84 @@ func (c *GitCommand) AbortMerge() error {
|
|||||||
return c.OSCommand.RunCommand("git merge --abort")
|
return c.OSCommand.RunCommand("git merge --abort")
|
||||||
}
|
}
|
||||||
|
|
||||||
// UsingGpg tells us whether the user has gpg enabled so that we can know
|
// usingGpg tells us whether the user has gpg enabled so that we can know
|
||||||
// whether we need to run a subprocess to allow them to enter their password
|
// whether we need to run a subprocess to allow them to enter their password
|
||||||
func (c *GitCommand) UsingGpg() bool {
|
func (c *GitCommand) usingGpg() bool {
|
||||||
gpgsign, _ := gitconfig.Global("commit.gpgsign")
|
gpgsign, _ := c.getLocalGitConfig("commit.gpgsign")
|
||||||
if gpgsign == "" {
|
if gpgsign == "" {
|
||||||
gpgsign, _ = gitconfig.Local("commit.gpgsign")
|
gpgsign, _ = c.getGlobalGitConfig("commit.gpgsign")
|
||||||
}
|
}
|
||||||
if gpgsign == "" {
|
value := strings.ToLower(gpgsign)
|
||||||
return false
|
|
||||||
}
|
return value == "true" || value == "1" || value == "yes" || value == "on"
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit commit to git
|
// Commit commits to git
|
||||||
func (c *GitCommand) Commit(g *gocui.Gui, message string) (*exec.Cmd, error) {
|
func (c *GitCommand) Commit(message string) (*exec.Cmd, error) {
|
||||||
command := "git commit -m " + c.OSCommand.Quote(message)
|
command := fmt.Sprintf("git commit -m %s", c.OSCommand.Quote(message))
|
||||||
if c.UsingGpg() {
|
if c.usingGpg() {
|
||||||
return c.OSCommand.PrepareSubProcess(c.OSCommand.Platform.shell, c.OSCommand.Platform.shellArg, command), nil
|
return c.OSCommand.PrepareSubProcess(c.OSCommand.Platform.shell, c.OSCommand.Platform.shellArg, command), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, c.OSCommand.RunCommand(command)
|
return nil, c.OSCommand.RunCommand(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull pull from repo
|
// Pull pulls from repo
|
||||||
func (c *GitCommand) Pull() error {
|
func (c *GitCommand) Pull() error {
|
||||||
return c.OSCommand.RunCommand("git pull --no-edit")
|
return c.OSCommand.RunCommand("git pull --no-edit")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push push to a branch
|
// Push pushes to a branch
|
||||||
func (c *GitCommand) Push(branchName string, force bool) error {
|
func (c *GitCommand) Push(branchName string, force bool) error {
|
||||||
forceFlag := ""
|
forceFlag := ""
|
||||||
if force {
|
if force {
|
||||||
forceFlag = "--force-with-lease "
|
forceFlag = "--force-with-lease "
|
||||||
}
|
}
|
||||||
return c.OSCommand.RunCommand("git push " + forceFlag + "-u origin " + branchName)
|
|
||||||
|
return c.OSCommand.RunCommand(fmt.Sprintf("git push %s -u origin %s", forceFlag, branchName))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SquashPreviousTwoCommits squashes a commit down to the one below it
|
// SquashPreviousTwoCommits squashes a commit down to the one below it
|
||||||
// retaining the message of the higher commit
|
// retaining the message of the higher commit
|
||||||
func (c *GitCommand) SquashPreviousTwoCommits(message string) error {
|
func (c *GitCommand) SquashPreviousTwoCommits(message string) error {
|
||||||
// TODO: test this
|
// TODO: test this
|
||||||
err := c.OSCommand.RunCommand("git reset --soft HEAD^")
|
if err := c.OSCommand.RunCommand("git reset --soft HEAD^"); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// TODO: if password is required, we need to return a subprocess
|
// TODO: if password is required, we need to return a subprocess
|
||||||
return c.OSCommand.RunCommand("git commit --amend -m " + c.OSCommand.Quote(message))
|
return c.OSCommand.RunCommand(fmt.Sprintf("git commit --amend -m %s", c.OSCommand.Quote(message)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SquashFixupCommit squashes a 'FIXUP' commit into the commit beneath it,
|
// SquashFixupCommit squashes a 'FIXUP' commit into the commit beneath it,
|
||||||
// retaining the commit message of the lower commit
|
// retaining the commit message of the lower commit
|
||||||
func (c *GitCommand) SquashFixupCommit(branchName string, shaValue string) error {
|
func (c *GitCommand) SquashFixupCommit(branchName string, shaValue string) error {
|
||||||
var err error
|
|
||||||
commands := []string{
|
commands := []string{
|
||||||
"git checkout -q " + shaValue,
|
fmt.Sprintf("git checkout -q %s", shaValue),
|
||||||
"git reset --soft " + shaValue + "^",
|
fmt.Sprintf("git reset --soft %s^", shaValue),
|
||||||
"git commit --amend -C " + shaValue + "^",
|
fmt.Sprintf("git commit --amend -C %s^", shaValue),
|
||||||
"git rebase --onto HEAD " + shaValue + " " + branchName,
|
fmt.Sprintf("git rebase --onto HEAD %s %s", shaValue, branchName),
|
||||||
}
|
}
|
||||||
ret := ""
|
|
||||||
for _, command := range commands {
|
for _, command := range commands {
|
||||||
c.Log.Info(command)
|
c.Log.Info(command)
|
||||||
output, err := c.OSCommand.RunCommandWithOutput(command)
|
|
||||||
ret += output
|
if output, err := c.OSCommand.RunCommandWithOutput(command); err != nil {
|
||||||
if err != nil {
|
ret := output
|
||||||
|
// We are already in an error state here so we're just going to append
|
||||||
|
// the output of these commands
|
||||||
|
output, _ := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git branch -d %s", shaValue))
|
||||||
|
ret += output
|
||||||
|
output, _ = c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git checkout %s", branchName))
|
||||||
|
ret += output
|
||||||
|
|
||||||
c.Log.Info(ret)
|
c.Log.Info(ret)
|
||||||
break
|
return errors.New(ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
// We are already in an error state here so we're just going to append
|
|
||||||
// the output of these commands
|
|
||||||
output, _ := c.OSCommand.RunCommandWithOutput("git branch -d " + shaValue)
|
|
||||||
ret += output
|
|
||||||
output, _ = c.OSCommand.RunCommandWithOutput("git checkout " + branchName)
|
|
||||||
ret += output
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(ret)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CatFile obtain the contents of a file
|
// CatFile obtains the content of a file
|
||||||
func (c *GitCommand) CatFile(fileName string) (string, error) {
|
func (c *GitCommand) CatFile(fileName string) (string, error) {
|
||||||
return c.OSCommand.RunCommandWithOutput("cat " + c.OSCommand.Quote(fileName))
|
return c.OSCommand.RunCommandWithOutput("cat " + c.OSCommand.Quote(fileName))
|
||||||
}
|
}
|
||||||
|
@ -56,9 +56,11 @@ func newDummyLog() *logrus.Entry {
|
|||||||
|
|
||||||
func newDummyGitCommand() *GitCommand {
|
func newDummyGitCommand() *GitCommand {
|
||||||
return &GitCommand{
|
return &GitCommand{
|
||||||
Log: newDummyLog(),
|
Log: newDummyLog(),
|
||||||
OSCommand: newDummyOSCommand(),
|
OSCommand: newDummyOSCommand(),
|
||||||
Tr: i18n.NewLocalizer(newDummyLog()),
|
Tr: i18n.NewLocalizer(newDummyLog()),
|
||||||
|
getGlobalGitConfig: func(string) (string, error) { return "", nil },
|
||||||
|
getLocalGitConfig: func(string) (string, error) { return "", nil },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,6 +732,353 @@ func TestGitCommandMerge(t *testing.T) {
|
|||||||
assert.NoError(t, gitCmd.Merge("test"))
|
assert.NoError(t, gitCmd.Merge("test"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGitCommandUsingGpg(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
getLocalGitConfig func(string) (string, error)
|
||||||
|
getGlobalGitConfig func(string) (string, error)
|
||||||
|
test func(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"Option global and local config commit.gpgsign is not set",
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
func(gpgEnabled bool) {
|
||||||
|
assert.False(t, gpgEnabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Option global config commit.gpgsign is not set, fallback on local config",
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "true", nil
|
||||||
|
},
|
||||||
|
func(gpgEnabled bool) {
|
||||||
|
assert.True(t, gpgEnabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Option commit.gpgsign is true",
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "True", nil
|
||||||
|
},
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
func(gpgEnabled bool) {
|
||||||
|
assert.True(t, gpgEnabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Option commit.gpgsign is on",
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "ON", nil
|
||||||
|
},
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
func(gpgEnabled bool) {
|
||||||
|
assert.True(t, gpgEnabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Option commit.gpgsign is yes",
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "YeS", nil
|
||||||
|
},
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
func(gpgEnabled bool) {
|
||||||
|
assert.True(t, gpgEnabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Option commit.gpgsign is 1",
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "1", nil
|
||||||
|
},
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
func(gpgEnabled bool) {
|
||||||
|
assert.True(t, gpgEnabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
gitCmd := newDummyGitCommand()
|
||||||
|
gitCmd.getGlobalGitConfig = s.getGlobalGitConfig
|
||||||
|
gitCmd.getLocalGitConfig = s.getLocalGitConfig
|
||||||
|
s.test(gitCmd.usingGpg())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGitCommandCommit(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
command func(string, ...string) *exec.Cmd
|
||||||
|
getGlobalGitConfig func(string) (string, error)
|
||||||
|
test func(*exec.Cmd, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"Commit using gpg",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "bash", cmd)
|
||||||
|
assert.EqualValues(t, []string{"-c", `git commit -m 'test'`}, args)
|
||||||
|
|
||||||
|
return exec.Command("echo")
|
||||||
|
},
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "true", nil
|
||||||
|
},
|
||||||
|
func(cmd *exec.Cmd, err error) {
|
||||||
|
assert.NotNil(t, cmd)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Commit without using gpg",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"commit", "-m", "test"}, args)
|
||||||
|
|
||||||
|
return exec.Command("echo")
|
||||||
|
},
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "false", nil
|
||||||
|
},
|
||||||
|
func(cmd *exec.Cmd, err error) {
|
||||||
|
assert.Nil(t, cmd)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Commit without using gpg with an error",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"commit", "-m", "test"}, args)
|
||||||
|
|
||||||
|
return exec.Command("exit", "1")
|
||||||
|
},
|
||||||
|
func(string) (string, error) {
|
||||||
|
return "false", nil
|
||||||
|
},
|
||||||
|
func(cmd *exec.Cmd, err error) {
|
||||||
|
assert.Nil(t, cmd)
|
||||||
|
assert.Error(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
gitCmd := newDummyGitCommand()
|
||||||
|
gitCmd.getGlobalGitConfig = s.getGlobalGitConfig
|
||||||
|
gitCmd.OSCommand.command = s.command
|
||||||
|
s.test(gitCmd.Commit("test"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGitCommandPush(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
command func(string, ...string) *exec.Cmd
|
||||||
|
forcePush bool
|
||||||
|
test func(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"Push with force disabled",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"push", "-u", "origin", "test"}, args)
|
||||||
|
|
||||||
|
return exec.Command("echo")
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
func(err error) {
|
||||||
|
assert.Nil(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Push with force enable",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"push", "--force-with-lease", "-u", "origin", "test"}, args)
|
||||||
|
|
||||||
|
return exec.Command("echo")
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
func(err error) {
|
||||||
|
assert.Nil(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Push with an error occurring",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"push", "-u", "origin", "test"}, args)
|
||||||
|
|
||||||
|
return exec.Command("exit", "1")
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
func(err error) {
|
||||||
|
assert.Error(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
gitCmd := newDummyGitCommand()
|
||||||
|
gitCmd.OSCommand.command = s.command
|
||||||
|
s.test(gitCmd.Push("test", s.forcePush))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGitCommandSquashPreviousTwoCommits(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
command func(string, ...string) *exec.Cmd
|
||||||
|
test func(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"Git reset triggers an error",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"reset", "--soft", "HEAD^"}, args)
|
||||||
|
|
||||||
|
return exec.Command("exit", "1")
|
||||||
|
},
|
||||||
|
func(err error) {
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Git commit triggers an error",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
if len(args) > 0 && args[0] == "reset" {
|
||||||
|
return exec.Command("echo")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"commit", "--amend", "-m", "test"}, args)
|
||||||
|
|
||||||
|
return exec.Command("exit", "1")
|
||||||
|
},
|
||||||
|
func(err error) {
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Stash succeeded",
|
||||||
|
func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
if len(args) > 0 && args[0] == "reset" {
|
||||||
|
return exec.Command("echo")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.EqualValues(t, "git", cmd)
|
||||||
|
assert.EqualValues(t, []string{"commit", "--amend", "-m", "test"}, args)
|
||||||
|
|
||||||
|
return exec.Command("echo")
|
||||||
|
},
|
||||||
|
func(err error) {
|
||||||
|
assert.Nil(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
gitCmd := newDummyGitCommand()
|
||||||
|
gitCmd.OSCommand.command = s.command
|
||||||
|
s.test(gitCmd.SquashPreviousTwoCommits("test"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGitCommandSquashFixupCommit(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
testName string
|
||||||
|
command func() (func(string, ...string) *exec.Cmd, *[][]string)
|
||||||
|
test func(*[][]string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
"An error occurred with one of the sub git command",
|
||||||
|
func() (func(string, ...string) *exec.Cmd, *[][]string) {
|
||||||
|
cmdsCalled := [][]string{}
|
||||||
|
return func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
cmdsCalled = append(cmdsCalled, args)
|
||||||
|
if len(args) > 0 && args[0] == "checkout" {
|
||||||
|
return exec.Command("exit", "1")
|
||||||
|
}
|
||||||
|
|
||||||
|
return exec.Command("echo")
|
||||||
|
}, &cmdsCalled
|
||||||
|
},
|
||||||
|
func(cmdsCalled *[][]string, err error) {
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Len(t, *cmdsCalled, 3)
|
||||||
|
assert.EqualValues(t, *cmdsCalled, [][]string{
|
||||||
|
{"checkout", "-q", "6789abcd"},
|
||||||
|
{"branch", "-d", "6789abcd"},
|
||||||
|
{"checkout", "test"},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Squash fixup succeeded",
|
||||||
|
func() (func(string, ...string) *exec.Cmd, *[][]string) {
|
||||||
|
cmdsCalled := [][]string{}
|
||||||
|
return func(cmd string, args ...string) *exec.Cmd {
|
||||||
|
cmdsCalled = append(cmdsCalled, args)
|
||||||
|
return exec.Command("echo")
|
||||||
|
}, &cmdsCalled
|
||||||
|
},
|
||||||
|
func(cmdsCalled *[][]string, err error) {
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Len(t, *cmdsCalled, 4)
|
||||||
|
assert.EqualValues(t, *cmdsCalled, [][]string{
|
||||||
|
{"checkout", "-q", "6789abcd"},
|
||||||
|
{"reset", "--soft", "6789abcd^"},
|
||||||
|
{"commit", "--amend", "-C", "6789abcd^"},
|
||||||
|
{"rebase", "--onto", "HEAD", "6789abcd", "test"},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.testName, func(t *testing.T) {
|
||||||
|
var cmdsCalled *[][]string
|
||||||
|
gitCmd := newDummyGitCommand()
|
||||||
|
gitCmd.OSCommand.command, cmdsCalled = s.command()
|
||||||
|
s.test(cmdsCalled, gitCmd.SquashFixupCommit("test", "6789abcd"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGitCommandDiff(t *testing.T) {
|
func TestGitCommandDiff(t *testing.T) {
|
||||||
gitCommand := newDummyGitCommand()
|
gitCommand := newDummyGitCommand()
|
||||||
assert.NoError(t, test.GenerateRepo("lots_of_diffs.sh"))
|
assert.NoError(t, test.GenerateRepo("lots_of_diffs.sh"))
|
||||||
|
@ -17,11 +17,12 @@ import (
|
|||||||
|
|
||||||
// Platform stores the os state
|
// Platform stores the os state
|
||||||
type Platform struct {
|
type Platform struct {
|
||||||
os string
|
os string
|
||||||
shell string
|
shell string
|
||||||
shellArg string
|
shellArg string
|
||||||
escapedQuote string
|
escapedQuote string
|
||||||
openCommand string
|
openCommand string
|
||||||
|
fallbackEscapedQuote string
|
||||||
}
|
}
|
||||||
|
|
||||||
// OSCommand holds all the os commands
|
// OSCommand holds all the os commands
|
||||||
@ -140,7 +141,11 @@ func (c *OSCommand) PrepareSubProcess(cmdName string, commandArgs ...string) *ex
|
|||||||
// Quote wraps a message in platform-specific quotation marks
|
// Quote wraps a message in platform-specific quotation marks
|
||||||
func (c *OSCommand) Quote(message string) string {
|
func (c *OSCommand) Quote(message string) string {
|
||||||
message = strings.Replace(message, "`", "\\`", -1)
|
message = strings.Replace(message, "`", "\\`", -1)
|
||||||
return c.Platform.escapedQuote + message + c.Platform.escapedQuote
|
escapedQuote := c.Platform.escapedQuote
|
||||||
|
if strings.Contains(message, c.Platform.escapedQuote) {
|
||||||
|
escapedQuote = c.Platform.fallbackEscapedQuote
|
||||||
|
}
|
||||||
|
return escapedQuote + message + escapedQuote
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unquote removes wrapping quotations marks if they are present
|
// Unquote removes wrapping quotations marks if they are present
|
||||||
|
@ -8,10 +8,11 @@ import (
|
|||||||
|
|
||||||
func getPlatform() *Platform {
|
func getPlatform() *Platform {
|
||||||
return &Platform{
|
return &Platform{
|
||||||
os: runtime.GOOS,
|
os: runtime.GOOS,
|
||||||
shell: "bash",
|
shell: "bash",
|
||||||
shellArg: "-c",
|
shellArg: "-c",
|
||||||
escapedQuote: "\"",
|
escapedQuote: "'",
|
||||||
openCommand: "open {{filename}}",
|
openCommand: "open {{filename}}",
|
||||||
|
fallbackEscapedQuote: "\"",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,6 +265,32 @@ func TestOSCommandQuote(t *testing.T) {
|
|||||||
assert.EqualValues(t, expected, actual)
|
assert.EqualValues(t, expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestOSCommandQuoteSingleQuote tests the quote function with ' quotes explicitly for Linux
|
||||||
|
func TestOSCommandQuoteSingleQuote(t *testing.T) {
|
||||||
|
osCommand := newDummyOSCommand()
|
||||||
|
|
||||||
|
osCommand.Platform.os = "linux"
|
||||||
|
|
||||||
|
actual := osCommand.Quote("hello 'test'")
|
||||||
|
|
||||||
|
expected := osCommand.Platform.fallbackEscapedQuote + "hello 'test'" + osCommand.Platform.fallbackEscapedQuote
|
||||||
|
|
||||||
|
assert.EqualValues(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestOSCommandQuoteSingleQuote tests the quote function with " quotes explicitly for Linux
|
||||||
|
func TestOSCommandQuoteDoubleQuote(t *testing.T) {
|
||||||
|
osCommand := newDummyOSCommand()
|
||||||
|
|
||||||
|
osCommand.Platform.os = "linux"
|
||||||
|
|
||||||
|
actual := osCommand.Quote(`hello "test"`)
|
||||||
|
|
||||||
|
expected := osCommand.Platform.escapedQuote + "hello \"test\"" + osCommand.Platform.escapedQuote
|
||||||
|
|
||||||
|
assert.EqualValues(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
func TestOSCommandUnquote(t *testing.T) {
|
func TestOSCommandUnquote(t *testing.T) {
|
||||||
osCommand := newDummyOSCommand()
|
osCommand := newDummyOSCommand()
|
||||||
|
|
||||||
|
@ -2,9 +2,10 @@ package commands
|
|||||||
|
|
||||||
func getPlatform() *Platform {
|
func getPlatform() *Platform {
|
||||||
return &Platform{
|
return &Platform{
|
||||||
os: "windows",
|
os: "windows",
|
||||||
shell: "cmd",
|
shell: "cmd",
|
||||||
shellArg: "/c",
|
shellArg: "/c",
|
||||||
escapedQuote: `\"`,
|
escapedQuote: `\"`,
|
||||||
|
fallbackEscapedQuote: "\\'",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
|
|||||||
if message == "" {
|
if message == "" {
|
||||||
return gui.createErrorPanel(g, gui.Tr.SLocalize("CommitWithoutMessageErr"))
|
return gui.createErrorPanel(g, gui.Tr.SLocalize("CommitWithoutMessageErr"))
|
||||||
}
|
}
|
||||||
sub, err := gui.GitCommand.Commit(g, message)
|
sub, err := gui.GitCommand.Commit(message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO need to find a way to send through this error
|
// TODO need to find a way to send through this error
|
||||||
if err != gui.Errors.ErrSubProcess {
|
if err != gui.Errors.ErrSubProcess {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user