summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml48
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md1
-rw-r--r--.gitignore3
-rw-r--r--README.md2
-rw-r--r--docs/Config.md4
-rw-r--r--docs/resources/colored-border-example.pngbin0 -> 90126 bytes
-rw-r--r--pkg/app/app.go5
-rw-r--r--pkg/commands/git.go8
-rw-r--r--pkg/gui/files_panel.go28
-rw-r--r--pkg/gui/gui.go8
-rw-r--r--pkg/i18n/english.go6
-rw-r--r--pkg/i18n/i18n.go70
-rw-r--r--pkg/i18n/i18n_test.go81
-rwxr-xr-xtest.sh14
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
diff --git a/README.md b/README.md
index 6b85ffbe1..28fe9c399 100644
--- a/README.md
+++ b/README.md
@@ -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
new file mode 100644
index 000000000..06bb7bf8b
--- /dev/null
+++ b/docs/resources/colored-border-example.png
Binary files differ
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