diff options
-rw-r--r-- | .circleci/config.yml | 48 | ||||
-rw-r--r-- | .github/ISSUE_TEMPLATE/bug_report.md | 1 | ||||
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | docs/Config.md | 4 | ||||
-rw-r--r-- | docs/resources/colored-border-example.png | bin | 0 -> 90126 bytes | |||
-rw-r--r-- | pkg/app/app.go | 5 | ||||
-rw-r--r-- | pkg/commands/git.go | 8 | ||||
-rw-r--r-- | pkg/gui/files_panel.go | 28 | ||||
-rw-r--r-- | pkg/gui/gui.go | 8 | ||||
-rw-r--r-- | pkg/i18n/english.go | 6 | ||||
-rw-r--r-- | pkg/i18n/i18n.go | 70 | ||||
-rw-r--r-- | pkg/i18n/i18n_test.go | 81 | ||||
-rwxr-xr-x | test.sh | 14 |
14 files changed, 210 insertions, 68 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index c5f520b70..0eef1a409 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,26 +1,42 @@ -# Golang CircleCI 2.0 configuration file -# -# Check https://circleci.com/docs/2.0/language-go/ for more details version: 2 jobs: build: docker: - # specify the version - - image: circleci/golang:1.9 + - image: circleci/golang:1.10 - # Specify service dependencies here if necessary - # CircleCI maintains a library of pre-built images - # documented at https://circleci.com/docs/2.0/circleci-images/ - # - image: circleci/postgres:9.4 + working_directory: /go/src/github.com/jesseduffield/lazygit + steps: + - checkout + - run: + name: Run tests + command: | + ./test.sh + - run: + name: Push on codecov result + command: | + bash <(curl -s https://codecov.io/bash) - #### TEMPLATE_NOTE: go expects specific checkout path representing url - #### expecting it in the form of - #### /go/src/github.com/circleci/go-tool - #### /go/src/bitbucket.org/circleci/go-tool + release: + docker: + - image: circleci/golang:1.10 working_directory: /go/src/github.com/jesseduffield/lazygit steps: - checkout + - run: + name: Run gorelease + command: | + curl -sL https://git.io/goreleaser | bash - # specify any bash command here prefixed with `run: ` - - run: go test -v ./... - - run: bash <(curl -s https://codecov.io/bash) +workflows: + version: 2 + build: + jobs: + - build + release: + jobs: + - release: + filters: + tags: + only: /v[0-9]+(\.[0-9]+)*/ + branches: + ignore: /.*/ diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1a96635a3..b10cb5f37 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -23,6 +23,7 @@ If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. Windows] - Lazygit Version [e.g. v0.1.45] + - The last commit id if you built project from sources (run : ```git-rev parse HEAD```) **Additional context** Add any other context about the problem here. diff --git a/.gitignore b/.gitignore index 304a2356f..f759e8a06 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ TODO.md # Tests test/repos/repo +coverage.txt # Binaries -lazygit
\ No newline at end of file +lazygit @@ -1,4 +1,4 @@ -# lazygit [![Go Report Card](https://goreportcard.com/badge/github.com/jesseduffield/lazygit)](https://goreportcard.com/report/github.com/jesseduffield/lazygit) +# lazygit [![CircleCI](https://circleci.com/gh/jesseduffield/lazygit.svg?style=svg)](https://circleci.com/gh/jesseduffield/lazygit) [![codecov](https://codecov.io/gh/jesseduffield/lazygit/branch/master/graph/badge.svg)](https://codecov.io/gh/jesseduffield/lazygit) [![Go Report Card](https://goreportcard.com/badge/github.com/jesseduffield/lazygit)](https://goreportcard.com/report/github.com/jesseduffield/lazygit) [![GolangCI](https://golangci.com/badges/github.com/jesseduffield/lazygit.svg)](https://golangci.com) [![GoDoc](https://godoc.org/github.com/jesseduffield/lazygit?status.svg)](http://godoc.org/github.com/jesseduffield/lazygit) [![GitHub tag](https://img.shields.io/github/tag/jesseduffield/lazygit.svg)]() A simple terminal UI for git commands, written in Go with the [gocui](https://github.com/jroimartin/gocui "gocui") library. diff --git a/docs/Config.md b/docs/Config.md index e6e2c3974..7e657adc4 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -37,3 +37,7 @@ The available attributes are: - bold - reverse # useful for high-contrast - underline + +## Example Coloring: + +![border example](/docs/resources/colored-border-example.png) diff --git a/docs/resources/colored-border-example.png b/docs/resources/colored-border-example.png Binary files differnew file mode 100644 index 000000000..06bb7bf8b --- /dev/null +++ b/docs/resources/colored-border-example.png diff --git a/pkg/app/app.go b/pkg/app/app.go index aaa925e53..20a97276e 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -51,10 +51,7 @@ func NewApp(config config.AppConfigurer) (*App, error) { return app, err } - app.Tr, err = i18n.NewLocalizer(app.Log) - if err != nil { - return app, err - } + app.Tr = i18n.NewLocalizer(app.Log) app.GitCommand, err = commands.NewGitCommand(app.Log, app.OSCommand) if err != nil { diff --git a/pkg/commands/git.go b/pkg/commands/git.go index 557e6a8c0..bf9aa6646 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -270,8 +270,12 @@ func (c *GitCommand) Pull() error { } // Push push to a branch -func (c *GitCommand) Push(branchName string) error { - return c.OSCommand.RunCommand("git push -u origin " + branchName) +func (c *GitCommand) Push(branchName string, force bool) error { + forceFlag := "" + if force { + forceFlag = "--force-with-lease " + } + return c.OSCommand.RunCommand("git push " + forceFlag + "-u origin " + branchName) } // SquashPreviousTwoCommits squashes a commit down to the one below it diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index d614cf5ef..5791a9d15 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -360,21 +360,35 @@ func (gui *Gui) pullFiles(g *gocui.Gui, v *gocui.View) error { return nil } -func (gui *Gui) pushFiles(g *gocui.Gui, v *gocui.View) error { - gui.createMessagePanel(g, v, "", gui.Tr.SLocalize("PushWait")) +func (gui *Gui) pushWithForceFlag(currentView *gocui.View, force bool) error { + if err := gui.createMessagePanel(gui.g, currentView, "", gui.Tr.SLocalize("PushWait")); err != nil { + return err + } go func() { branchName := gui.State.Branches[0].Name - if err := gui.GitCommand.Push(branchName); err != nil { - gui.createErrorPanel(g, err.Error()) + if err := gui.GitCommand.Push(branchName, force); err != nil { + _ = gui.createErrorPanel(gui.g, err.Error()) } else { - gui.closeConfirmationPrompt(g) - gui.refreshCommits(g) - gui.refreshStatus(g) + _ = gui.closeConfirmationPrompt(gui.g) + _ = gui.refreshCommits(gui.g) + _ = gui.refreshStatus(gui.g) } }() return nil } +func (gui *Gui) pushFiles(g *gocui.Gui, v *gocui.View) error { + // if we have pullables we'll ask if the user wants to force push + _, pullables := gui.GitCommand.UpstreamDifferenceCount() + if pullables == "?" || pullables == "0" { + return gui.pushWithForceFlag(v, false) + } + err := gui.createConfirmationPanel(g, nil, gui.Tr.SLocalize("ForcePush"), gui.Tr.SLocalize("ForcePushPrompt"), func(g *gocui.Gui, v *gocui.View) error { + return gui.pushWithForceFlag(v, true) + }, nil) + return err +} + func (gui *Gui) handleSwitchToMerge(g *gocui.Gui, v *gocui.View) error { mergeView, err := g.View("main") if err != nil { diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 1e7b6156b..66777b3a6 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -141,14 +141,15 @@ func max(a, b int) int { func (gui *Gui) layout(g *gocui.Gui) error { g.Highlight = true width, height := g.Size() + version := gui.Config.GetVersion() leftSideWidth := width / 3 statusFilesBoundary := 2 filesBranchesBoundary := 2 * height / 5 // height - 20 commitsBranchesBoundary := 3 * height / 5 // height - 10 commitsStashBoundary := height - 5 // height - 5 + optionsVersionBoundary := width - max(len(version), 1) minimumHeight := 16 minimumWidth := 10 - version := gui.Config.GetVersion() panelSpacing := 1 if OverlappingEdges { @@ -227,7 +228,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { v.FgColor = gocui.ColorWhite } - if v, err := g.SetView("options", -1, optionsTop, width-len(version)-2, optionsTop+2, 0); err != nil { + if v, err := g.SetView("options", -1, optionsTop, optionsVersionBoundary-1, optionsTop+2, 0); err != nil { if err != gocui.ErrUnknownView { return err } @@ -249,8 +250,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { commitMessageView.Editable = true } } - - if v, err := g.SetView("version", width-len(version)-1, optionsTop, width, optionsTop+2, 0); err != nil { + if v, err := g.SetView("version", optionsVersionBoundary-1, optionsTop, width, optionsTop+2, 0); err != nil { if err != gocui.ErrUnknownView { return err } diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index bebe9b282..c0384136b 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -300,6 +300,12 @@ func addEnglish(i18nObject *i18n.Bundle) error { }, &i18n.Message{ ID: "EditConfig", Other: "edit config file", + }, &i18n.Message{ + ID: "ForcePush", + Other: "Force push", + }, &i18n.Message{ + ID: "ForcePushPrompt", + Other: "Your branch has diverged from the remote branch. Press 'esc' to cancel, or 'enter' to force push.", }, ) } diff --git a/pkg/i18n/i18n.go b/pkg/i18n/i18n.go index e209d55c5..bb97cc9a0 100644 --- a/pkg/i18n/i18n.go +++ b/pkg/i18n/i18n.go @@ -18,33 +18,12 @@ type Localizer struct { } // NewLocalizer creates a new Localizer -func NewLocalizer(log *logrus.Logger) (*Localizer, error) { +func NewLocalizer(log *logrus.Logger) *Localizer { + userLang := detectLanguage(jibber_jabber.DetectLanguage) - // detect the user's language - userLang, err := jibber_jabber.DetectLanguage() - if err != nil { - if err.Error() != "Could not detect Language" { - return nil, err - } - userLang = "C" - } log.Info("language: " + userLang) - // create a i18n bundle that can be used to add translations and other things - i18nBundle := &i18n.Bundle{DefaultLanguage: language.English} - - addBundles(log, i18nBundle) - - // return the new localizer that can be used to translate text - i18nLocalizer := i18n.NewLocalizer(i18nBundle, userLang) - - localizer := &Localizer{ - i18nLocalizer: i18nLocalizer, - language: userLang, - Log: log, - } - - return localizer, nil + return setupLocalizer(log, userLang) } // Localize handels the translations @@ -82,17 +61,42 @@ func (l *Localizer) GetLanguage() string { // add translation file(s) func addBundles(log *logrus.Logger, i18nBundle *i18n.Bundle) { - err := addPolish(i18nBundle) - if err != nil { - log.Fatal(err) + fs := []func(*i18n.Bundle) error{ + addPolish, + addDutch, + addEnglish, } - err = addDutch(i18nBundle) - if err != nil { - log.Fatal(err) + + for _, f := range fs { + if err := f(i18nBundle); err != nil { + log.Fatal(err) + + } } - err = addEnglish(i18nBundle) - if err != nil { - log.Fatal(err) +} + +// detectLanguage extracts user language from environment +func detectLanguage(langDetector func() (string, error)) string { + if userLang, err := langDetector(); err == nil { + return userLang } + return "C" +} + +// setupLocalizer creates a new localizer using given userLang +func setupLocalizer(log *logrus.Logger, userLang string) *Localizer { + // create a i18n bundle that can be used to add translations and other things + i18nBundle := &i18n.Bundle{DefaultLanguage: language.English} + + addBundles(log, i18nBundle) + + // return the new localizer that can be used to translate text + i18nLocalizer := i18n.NewLocalizer(i18nBundle, userLang) + + return &Localizer{ + i18nLocalizer: i18nLocalizer, + language: userLang, + Log: log, + } } diff --git a/pkg/i18n/i18n_test.go b/pkg/i18n/i18n_test.go new file mode 100644 index 000000000..481a40863 --- /dev/null +++ b/pkg/i18n/i18n_test.go @@ -0,0 +1,81 @@ +package i18n + +import ( + "fmt" + "testing" + + "github.com/nicksnyder/go-i18n/v2/i18n" + + "github.com/Sirupsen/logrus" + "github.com/stretchr/testify/assert" +) + +func TestNewLocalizer(t *testing.T) { + assert.NotNil(t, NewLocalizer(logrus.New())) +} + +func TestDetectLanguage(t *testing.T) { + type scenario struct { + langDetector func() (string, error) + expected string + } + + scenarios := []scenario{ + { + func() (string, error) { + return "", fmt.Errorf("An error occurred") + }, + "C", + }, + { + func() (string, error) { + return "en", nil + }, + "en", + }, + } + + for _, s := range scenarios { + assert.EqualValues(t, s.expected, detectLanguage(s.langDetector)) + } +} + +func TestLocalizer(t *testing.T) { + type scenario struct { + userLang string + test func(*Localizer) + } + + scenarios := []scenario{ + { + "C", + func(l *Localizer) { + assert.EqualValues(t, "C", l.GetLanguage()) + assert.Equal(t, "Diff", l.Localize(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "DiffTitle", + }, + })) + assert.Equal(t, "Diff", l.SLocalize("DiffTitle")) + assert.Equal(t, "Are you sure you want delete the branch test ?", l.TemplateLocalize("DeleteBranchMessage", Teml{"selectedBranchName": "test"})) + }, + }, + { + "nl", + func(l *Localizer) { + assert.EqualValues(t, "nl", l.GetLanguage()) + assert.Equal(t, "Diff", l.Localize(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "DiffTitle", + }, + })) + assert.Equal(t, "Diff", l.SLocalize("DiffTitle")) + assert.Equal(t, "Weet je zeker dat je test branch wil verwijderen?", l.TemplateLocalize("DeleteBranchMessage", Teml{"selectedBranchName": "test"})) + }, + }, + } + + for _, s := range scenarios { + s.test(setupLocalizer(logrus.New(), s.userLang)) + } +} diff --git a/test.sh b/test.sh new file mode 100755 index 000000000..a92243cf7 --- /dev/null +++ b/test.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -e +echo "" > coverage.txt + +for d in $( find ./* -maxdepth 10 ! -path "./vendor*" ! -path "./.git*" -type d); do + if ls $d/*.go &> /dev/null; then + go test -v -race -coverprofile=profile.out -covermode=atomic $d + if [ -f profile.out ]; then + cat profile.out >> coverage.txt + rm profile.out + fi + fi +done |