mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-11-28 09:08:41 +02:00
Merge pull request #2137 from jesseduffield/more-integration-tests
This commit is contained in:
commit
ee348751a0
@ -13,7 +13,7 @@ Usage:
|
||||
See https://github.com/jesseduffield/lazygit/tree/master/pkg/integration/README.md
|
||||
|
||||
CLI mode:
|
||||
> go run cmd/integration_test/main.go cli [--slow] <test1> <test2> ...
|
||||
> go run cmd/integration_test/main.go cli [--slow] [--sandbox] <test1> <test2> ...
|
||||
If you pass no test names, it runs all tests
|
||||
Accepted environment variables:
|
||||
KEY_PRESS_DELAY (e.g. 200): the number of milliseconds to wait between keypresses
|
||||
@ -42,12 +42,19 @@ func main() {
|
||||
case "cli":
|
||||
testNames := os.Args[2:]
|
||||
slow := false
|
||||
sandbox := false
|
||||
// get the next arg if it's --slow
|
||||
if len(os.Args) > 2 && (os.Args[2] == "--slow" || os.Args[2] == "-slow") {
|
||||
testNames = os.Args[3:]
|
||||
slow = true
|
||||
if len(os.Args) > 2 {
|
||||
if os.Args[2] == "--slow" || os.Args[2] == "-slow" {
|
||||
testNames = os.Args[3:]
|
||||
slow = true
|
||||
} else if os.Args[2] == "--sandbox" || os.Args[2] == "-sandbox" {
|
||||
testNames = os.Args[3:]
|
||||
sandbox = true
|
||||
}
|
||||
}
|
||||
clients.RunCLI(testNames, slow)
|
||||
|
||||
clients.RunCLI(testNames, slow, sandbox)
|
||||
case "tui":
|
||||
clients.RunTUI()
|
||||
default:
|
||||
|
8
go.mod
8
go.mod
@ -11,14 +11,14 @@ require (
|
||||
github.com/creack/pty v1.1.11
|
||||
github.com/fsmiamoto/git-todo-parser v0.0.2
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/gdamore/tcell/v2 v2.5.2
|
||||
github.com/gdamore/tcell/v2 v2.5.3
|
||||
github.com/go-errors/errors v1.4.2
|
||||
github.com/gookit/color v1.4.2
|
||||
github.com/imdario/mergo v0.3.11
|
||||
github.com/integrii/flaggy v1.4.0
|
||||
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
|
||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20220815095708-156fda5e0419
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20220916034937-22d48fda22d6
|
||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
|
||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
||||
github.com/jesseduffield/yaml v2.1.0+incompatible
|
||||
@ -61,13 +61,13 @@ require (
|
||||
github.com/onsi/ginkgo v1.10.3 // indirect
|
||||
github.com/onsi/gomega v1.7.1 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
|
||||
github.com/rivo/uniseg v0.3.4 // indirect
|
||||
github.com/rivo/uniseg v0.4.2 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.2.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect
|
||||
golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
|
16
go.sum
16
go.sum
@ -35,8 +35,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
|
||||
github.com/gdamore/tcell/v2 v2.5.2 h1:tKzG29kO9p2V++3oBY2W9zUjYu7IK1MENFeY/BzJSVY=
|
||||
github.com/gdamore/tcell/v2 v2.5.2/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo=
|
||||
github.com/gdamore/tcell/v2 v2.5.3 h1:b9XQrT6QGbgI7JvZOJXFNczOQeIYbo8BfeSMzt2sAV0=
|
||||
github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo=
|
||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
@ -72,8 +72,8 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
|
||||
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
|
||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg=
|
||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20220815095708-156fda5e0419 h1:p3Ix7RUcy4X16Lk5jTSfTxecJT7ryqYHclfRbo/Svzs=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20220815095708-156fda5e0419/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20220916034937-22d48fda22d6 h1:FgxhH7++BaLcDwldyNtxkeVUC2z7ur2QYtJ8Msgkgc0=
|
||||
github.com/jesseduffield/gocui v0.3.1-0.20220916034937-22d48fda22d6/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU=
|
||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
|
||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
|
||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U=
|
||||
@ -134,8 +134,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.3.4 h1:3Z3Eu6FGHZWSfNKJTOUiPatWwfc7DzJRU04jFUqJODw=
|
||||
github.com/rivo/uniseg v0.3.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8=
|
||||
github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
||||
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/samber/lo v1.10.1 h1:0D3h7i0U3hRAbaCeQ82DLe67n0A7Bbl0/cEoWqFGp+U=
|
||||
@ -194,8 +194,8 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc=
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc=
|
||||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
@ -494,8 +494,6 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error {
|
||||
})
|
||||
deadlock.Opts.Disable = !gui.Debug
|
||||
|
||||
gui.handleTestMode(startArgs.IntegrationTest)
|
||||
|
||||
gui.g.OnSearchEscape = gui.onSearchEscape
|
||||
if err := gui.Config.ReloadUserConfig(); err != nil {
|
||||
return nil
|
||||
@ -552,6 +550,8 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error {
|
||||
|
||||
gui.c.Log.Info("starting main loop")
|
||||
|
||||
gui.handleTestMode(startArgs.IntegrationTest)
|
||||
|
||||
return gui.g.MainLoop()
|
||||
}
|
||||
|
||||
|
@ -79,3 +79,11 @@ func (self *GuiDriver) MainView() *gocui.View {
|
||||
func (self *GuiDriver) SecondaryView() *gocui.View {
|
||||
return self.gui.secondaryView()
|
||||
}
|
||||
|
||||
func (self *GuiDriver) View(viewName string) *gocui.View {
|
||||
view, err := self.gui.g.View(viewName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
@ -53,10 +53,17 @@ func (gui *Gui) modeStatuses() []modeStatus {
|
||||
{
|
||||
isActive: gui.State.Modes.CherryPicking.Active,
|
||||
description: func() string {
|
||||
copiedCount := len(gui.State.Modes.CherryPicking.CherryPickedCommits)
|
||||
text := gui.c.Tr.LcCommitsCopied
|
||||
if copiedCount == 1 {
|
||||
text = gui.c.Tr.LcCommitCopied
|
||||
}
|
||||
|
||||
return gui.withResetButton(
|
||||
fmt.Sprintf(
|
||||
"%d commits copied",
|
||||
len(gui.State.Modes.CherryPicking.CherryPickedCommits),
|
||||
"%d %s",
|
||||
copiedCount,
|
||||
text,
|
||||
),
|
||||
style.FgCyan,
|
||||
)
|
||||
|
@ -42,7 +42,7 @@ func (gui *Gui) handleTestMode(test integrationTypes.IntegrationTest) {
|
||||
if Replaying() {
|
||||
gui.g.RecordingConfig = gocui.RecordingConfig{
|
||||
Speed: GetRecordingSpeed(),
|
||||
Leeway: 100,
|
||||
Leeway: 1000,
|
||||
}
|
||||
|
||||
var err error
|
||||
|
@ -507,6 +507,8 @@ type TranslationSet struct {
|
||||
EmptyOutput string
|
||||
Patch string
|
||||
CustomPatch string
|
||||
LcCommitsCopied string
|
||||
LcCommitCopied string
|
||||
Actions Actions
|
||||
Bisect Bisect
|
||||
}
|
||||
@ -1147,6 +1149,8 @@ func EnglishTranslationSet() TranslationSet {
|
||||
EmptyOutput: "<empty output>",
|
||||
Patch: "Patch",
|
||||
CustomPatch: "Custom patch",
|
||||
LcCommitsCopied: "commits copied",
|
||||
LcCommitCopied: "commit copied",
|
||||
Actions: Actions{
|
||||
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
|
||||
CheckoutCommit: "Checkout commit",
|
||||
|
@ -11,7 +11,7 @@ go run cmd/integration_test/main.go tui
|
||||
or
|
||||
|
||||
```sh
|
||||
go run cmd/integration_test/main.go cli [--slow] [testname or testpath...]
|
||||
go run cmd/integration_test/main.go cli [--slow or --sandbox] [testname or testpath...]
|
||||
```
|
||||
|
||||
## Writing tests
|
||||
@ -49,7 +49,7 @@ If you find yourself doing something frequently in a test, consider making it a
|
||||
|
||||
There are three ways to invoke a test:
|
||||
|
||||
1. go run cmd/integration_test/main.go cli [--slow] [testname or testpath...]
|
||||
1. go run cmd/integration_test/main.go cli [--slow or --sandbox] [testname or testpath...]
|
||||
2. go run cmd/integration_test/main.go tui
|
||||
3. go test pkg/integration/clients/go_test.go
|
||||
|
||||
@ -69,7 +69,7 @@ At the moment (this is subject to change) each test has a snapshot repo created
|
||||
|
||||
Say you want to do a manual test of how lazygit handles merge-conflicts, but you can't be bothered actually finding a way to create merge conflicts in a repo. To make your life easier, you can simply run a merge-conflicts test in sandbox mode, meaning the setup step is run for you, and then instead of the test driving the lazygit session, you're allowed to drive it yourself.
|
||||
|
||||
To run a test in sandbox mode you can press 's' on a test in the test TUI or pass the env var MODE=sandbox to the test runner.
|
||||
To run a test in sandbox mode you can press 's' on a test in the test TUI or in the test runner pass MODE=sandbox or the --sandbox argument.
|
||||
|
||||
## Migration process
|
||||
|
||||
|
@ -23,26 +23,34 @@ import (
|
||||
|
||||
// If invoked directly, you can specify tests to run by passing their names as positional arguments
|
||||
|
||||
func RunCLI(testNames []string, slow bool) {
|
||||
func RunCLI(testNames []string, slow bool, sandbox bool) {
|
||||
keyPressDelay := tryConvert(os.Getenv("KEY_PRESS_DELAY"), 0)
|
||||
if slow {
|
||||
keyPressDelay = SLOW_KEY_PRESS_DELAY
|
||||
}
|
||||
|
||||
var mode components.Mode
|
||||
if sandbox {
|
||||
mode = components.SANDBOX
|
||||
} else {
|
||||
mode = getModeFromEnv()
|
||||
}
|
||||
|
||||
err := components.RunTests(
|
||||
getTestsToRun(testNames),
|
||||
log.Printf,
|
||||
runCmdInTerminal,
|
||||
runAndPrintError,
|
||||
getModeFromEnv(),
|
||||
runAndPrintFatalError,
|
||||
mode,
|
||||
keyPressDelay,
|
||||
1,
|
||||
)
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func runAndPrintError(test *components.IntegrationTest, f func() error) {
|
||||
func runAndPrintFatalError(test *components.IntegrationTest, f func() error) {
|
||||
if err := f(); err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ package clients
|
||||
// for an example
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@ -39,12 +41,16 @@ func TestIntegration(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Run(test.Name(), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := f()
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
},
|
||||
components.CHECK_SNAPSHOT,
|
||||
0,
|
||||
// allowing two attempts at the test. If a test fails intermittently,
|
||||
// there may be a concurrency issue that we need to resolve.
|
||||
2,
|
||||
)
|
||||
|
||||
assert.NoError(t, err)
|
||||
@ -57,12 +63,26 @@ func runCmdHeadless(cmd *exec.Cmd) error {
|
||||
"TERM=xterm",
|
||||
)
|
||||
|
||||
f, err := pty.StartWithSize(cmd, &pty.Winsize{Rows: 100, Cols: 100})
|
||||
// not writing stderr to the pty because we want to capture a panic if
|
||||
// there is one. But some commands will not be in tty mode if stderr is
|
||||
// not a terminal. We'll need to keep an eye out for that.
|
||||
stderr := new(bytes.Buffer)
|
||||
cmd.Stderr = stderr
|
||||
|
||||
// these rows and columns are ignored because internally we use tcell's
|
||||
// simulation screen. However we still need the pty for the sake of
|
||||
// running other commands in a pty.
|
||||
f, err := pty.StartWithSize(cmd, &pty.Winsize{Rows: 300, Cols: 300})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, _ = io.Copy(ioutil.Discard, f)
|
||||
|
||||
if cmd.Wait() != nil {
|
||||
// return an error with the stderr output
|
||||
return errors.New(stderr.String())
|
||||
}
|
||||
|
||||
return f.Close()
|
||||
}
|
||||
|
@ -375,8 +375,15 @@ func runTuiTest(test *components.IntegrationTest, mode components.Mode, keyPress
|
||||
runAndPrintError,
|
||||
mode,
|
||||
keyPressDelay,
|
||||
1,
|
||||
)
|
||||
if err != nil {
|
||||
log.Println(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func runAndPrintError(test *components.IntegrationTest, f func() error) {
|
||||
if err := f(); err != nil {
|
||||
log.Println(err.Error())
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,13 @@ func (self *matcher) context(prefix string) *matcher {
|
||||
|
||||
func Contains(target string) *matcher {
|
||||
return &matcher{testFn: func(value string) (bool, string) {
|
||||
return strings.Contains(value, target), fmt.Sprintf("Expected '%s' to contain '%s'", value, target)
|
||||
return strings.Contains(value, target), fmt.Sprintf("Expected '%s' to be found in '%s'", target, value)
|
||||
}}
|
||||
}
|
||||
|
||||
func NotContains(target string) *matcher {
|
||||
return &matcher{testFn: func(value string) (bool, string) {
|
||||
return !strings.Contains(value, target), fmt.Sprintf("Expected '%s' to NOT be found in '%s'", target, value)
|
||||
}}
|
||||
}
|
||||
|
||||
@ -78,6 +84,14 @@ func (self *Assert) CommitCount(expectedCount int) {
|
||||
})
|
||||
}
|
||||
|
||||
func (self *Assert) AtLeastOneCommit() {
|
||||
self.assertWithRetries(func() (bool, string) {
|
||||
actualCount := len(self.gui.Model().Commits)
|
||||
|
||||
return actualCount > 0, "Expected at least one commit present"
|
||||
})
|
||||
}
|
||||
|
||||
func (self *Assert) MatchHeadCommitMessage(matcher *matcher) {
|
||||
self.assertWithRetries(func() (bool, string) {
|
||||
return len(self.gui.Model().Commits) > 0, "Expected at least one commit to be present"
|
||||
@ -97,6 +111,13 @@ func (self *Assert) CurrentViewName(expectedViewName string) {
|
||||
})
|
||||
}
|
||||
|
||||
func (self *Assert) CurrentWindowName(expectedWindowName string) {
|
||||
self.assertWithRetries(func() (bool, string) {
|
||||
actual := self.gui.CurrentContext().GetView().Name()
|
||||
return actual == expectedWindowName, fmt.Sprintf("Expected current window name to be '%s', but got '%s'", expectedWindowName, actual)
|
||||
})
|
||||
}
|
||||
|
||||
func (self *Assert) CurrentBranchName(expectedViewName string) {
|
||||
self.assertWithRetries(func() (bool, string) {
|
||||
actual := self.gui.CheckedOutRef().Name
|
||||
@ -156,6 +177,22 @@ func (self *Assert) MatchCurrentViewTitle(matcher *matcher) {
|
||||
)
|
||||
}
|
||||
|
||||
func (self *Assert) MatchViewContent(viewName string, matcher *matcher) {
|
||||
self.matchString(matcher, fmt.Sprintf("Unexpected content in view '%s'.", viewName),
|
||||
func() string {
|
||||
return self.gui.View(viewName).Buffer()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (self *Assert) MatchCurrentViewContent(matcher *matcher) {
|
||||
self.matchString(matcher, "Unexpected content in current view.",
|
||||
func() string {
|
||||
return self.gui.CurrentContext().GetView().Buffer()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (self *Assert) MatchMainViewContent(matcher *matcher) {
|
||||
self.matchString(matcher, "Unexpected main view content.",
|
||||
func() string {
|
||||
@ -180,7 +217,7 @@ func (self *Assert) matchString(matcher *matcher, context string, getValue func(
|
||||
}
|
||||
|
||||
func (self *Assert) assertWithRetries(test func() (bool, string)) {
|
||||
waitTimes := []int{0, 1, 5, 10, 200, 500, 1000}
|
||||
waitTimes := []int{0, 1, 5, 10, 200, 500, 1000, 2000, 4000}
|
||||
|
||||
var message string
|
||||
for _, waitTime := range waitTimes {
|
||||
|
@ -42,22 +42,27 @@ func (self *Input) pressKey(keyStr string) {
|
||||
|
||||
func (self *Input) SwitchToStatusWindow() {
|
||||
self.pressKey(self.keys.Universal.JumpToBlock[0])
|
||||
self.assert.CurrentWindowName("status")
|
||||
}
|
||||
|
||||
func (self *Input) SwitchToFilesWindow() {
|
||||
self.pressKey(self.keys.Universal.JumpToBlock[1])
|
||||
self.assert.CurrentWindowName("files")
|
||||
}
|
||||
|
||||
func (self *Input) SwitchToBranchesWindow() {
|
||||
self.pressKey(self.keys.Universal.JumpToBlock[2])
|
||||
self.assert.CurrentWindowName("localBranches")
|
||||
}
|
||||
|
||||
func (self *Input) SwitchToCommitsWindow() {
|
||||
self.pressKey(self.keys.Universal.JumpToBlock[3])
|
||||
self.assert.CurrentWindowName("commits")
|
||||
}
|
||||
|
||||
func (self *Input) SwitchToStashWindow() {
|
||||
self.pressKey(self.keys.Universal.JumpToBlock[4])
|
||||
self.assert.CurrentWindowName("stash")
|
||||
}
|
||||
|
||||
func (self *Input) Type(content string) {
|
||||
@ -71,6 +76,11 @@ func (self *Input) Confirm() {
|
||||
self.pressKey(self.keys.Universal.Confirm)
|
||||
}
|
||||
|
||||
// i.e. same as Confirm
|
||||
func (self *Input) Enter() {
|
||||
self.pressKey(self.keys.Universal.Confirm)
|
||||
}
|
||||
|
||||
// i.e. pressing escape
|
||||
func (self *Input) Cancel() {
|
||||
self.pressKey(self.keys.Universal.Return)
|
||||
@ -132,35 +142,43 @@ func (self *Input) NavigateToListItemContainingText(text string) {
|
||||
|
||||
view := currentContext.GetView()
|
||||
|
||||
// first we look for a duplicate on the current screen. We won't bother looking beyond that though.
|
||||
matchCount := 0
|
||||
matchIndex := -1
|
||||
for i, line := range view.ViewBufferLines() {
|
||||
if strings.Contains(line, text) {
|
||||
matchCount++
|
||||
matchIndex = i
|
||||
}
|
||||
}
|
||||
if matchCount > 1 {
|
||||
self.assert.Fail(fmt.Sprintf("Found %d matches for %s, expected only a single match", matchCount, text))
|
||||
}
|
||||
if matchCount == 1 {
|
||||
selectedLineIdx := view.SelectedLineIdx()
|
||||
if selectedLineIdx == matchIndex {
|
||||
return
|
||||
}
|
||||
if selectedLineIdx < matchIndex {
|
||||
for i := selectedLineIdx; i < matchIndex; i++ {
|
||||
self.NextItem()
|
||||
}
|
||||
return
|
||||
} else {
|
||||
for i := selectedLineIdx; i > matchIndex; i-- {
|
||||
self.PreviousItem()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
var matchIndex int
|
||||
|
||||
self.assert.Fail(fmt.Sprintf("Could not find item containing text: %s", text))
|
||||
self.assert.assertWithRetries(func() (bool, string) {
|
||||
matchCount := 0
|
||||
matchIndex = -1
|
||||
// first we look for a duplicate on the current screen. We won't bother looking beyond that though.
|
||||
for i, line := range view.ViewBufferLines() {
|
||||
if strings.Contains(line, text) {
|
||||
matchCount++
|
||||
matchIndex = i
|
||||
}
|
||||
}
|
||||
if matchCount > 1 {
|
||||
return false, fmt.Sprintf("Found %d matches for %s, expected only a single match", matchCount, text)
|
||||
} else if matchCount == 0 {
|
||||
return false, fmt.Sprintf("Could not find item containing text: %s", text)
|
||||
} else {
|
||||
return true, ""
|
||||
}
|
||||
})
|
||||
|
||||
selectedLineIdx := view.SelectedLineIdx()
|
||||
if selectedLineIdx == matchIndex {
|
||||
self.assert.MatchSelectedLine(Contains(text))
|
||||
return
|
||||
}
|
||||
if selectedLineIdx < matchIndex {
|
||||
for i := selectedLineIdx; i < matchIndex; i++ {
|
||||
self.NextItem()
|
||||
}
|
||||
self.assert.MatchSelectedLine(Contains(text))
|
||||
return
|
||||
} else {
|
||||
for i := selectedLineIdx; i > matchIndex; i-- {
|
||||
self.PreviousItem()
|
||||
}
|
||||
self.assert.MatchSelectedLine(Contains(text))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ func RunTests(
|
||||
testWrapper func(test *IntegrationTest, f func() error),
|
||||
mode Mode,
|
||||
keyPressDelay int,
|
||||
maxAttempts int,
|
||||
) error {
|
||||
projectRootDir := utils.GetLazygitRootDirectory()
|
||||
err := os.Chdir(projectRootDir)
|
||||
@ -58,12 +59,24 @@ func RunTests(
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
|
||||
paths := NewPaths(
|
||||
filepath.Join(testDir, test.Name()),
|
||||
)
|
||||
|
||||
testWrapper(test, func() error { //nolint: thelper
|
||||
return runTest(test, paths, projectRootDir, logf, runCmd, mode, keyPressDelay)
|
||||
paths := NewPaths(
|
||||
filepath.Join(testDir, test.Name()),
|
||||
)
|
||||
|
||||
for i := 0; i < maxAttempts; i++ {
|
||||
err := runTest(test, paths, projectRootDir, logf, runCmd, mode, keyPressDelay)
|
||||
if err != nil {
|
||||
if i == maxAttempts-1 {
|
||||
return err
|
||||
}
|
||||
logf("retrying test %s", test.Name())
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@ -126,16 +139,7 @@ func buildLazygit() error {
|
||||
}
|
||||
|
||||
func createFixture(test *IntegrationTest, paths Paths) error {
|
||||
originalDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Chdir(paths.ActualRepo()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
shell := NewShell()
|
||||
shell := NewShell(paths.ActualRepo())
|
||||
shell.RunCommand("git init -b master")
|
||||
shell.RunCommand(`git config user.email "CI@example.com"`)
|
||||
shell.RunCommand(`git config user.name "CI"`)
|
||||
@ -143,10 +147,6 @@ func createFixture(test *IntegrationTest, paths Paths) error {
|
||||
|
||||
test.SetupRepo(shell)
|
||||
|
||||
if err := os.Chdir(originalDir); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/secureexec"
|
||||
"github.com/mgutz/str"
|
||||
@ -12,16 +13,20 @@ import (
|
||||
// this is for running shell commands, mostly for the sake of setting up the repo
|
||||
// but you can also run the commands from within lazygit to emulate things happening
|
||||
// in the background.
|
||||
type Shell struct{}
|
||||
type Shell struct {
|
||||
// working directory the shell is invoked in
|
||||
dir string
|
||||
}
|
||||
|
||||
func NewShell() *Shell {
|
||||
return &Shell{}
|
||||
func NewShell(dir string) *Shell {
|
||||
return &Shell{dir: dir}
|
||||
}
|
||||
|
||||
func (s *Shell) RunCommand(cmdStr string) *Shell {
|
||||
args := str.ToArgv(cmdStr)
|
||||
cmd := secureexec.Command(args[0], args[1:]...)
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Dir = s.dir
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
@ -32,9 +37,20 @@ func (s *Shell) RunCommand(cmdStr string) *Shell {
|
||||
}
|
||||
|
||||
func (s *Shell) CreateFile(path string, content string) *Shell {
|
||||
err := ioutil.WriteFile(path, []byte(content), 0o644)
|
||||
fullPath := filepath.Join(s.dir, path)
|
||||
err := ioutil.WriteFile(fullPath, []byte(content), 0o644)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("error creating file: %s\n%s", path, err))
|
||||
panic(fmt.Sprintf("error creating file: %s\n%s", fullPath, err))
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Shell) UpdateFile(path string, content string) *Shell {
|
||||
fullPath := filepath.Join(s.dir, path)
|
||||
err := ioutil.WriteFile(fullPath, []byte(content), 0o644)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("error updating file: %s\n%s", fullPath, err))
|
||||
}
|
||||
|
||||
return s
|
||||
@ -44,6 +60,10 @@ func (s *Shell) NewBranch(name string) *Shell {
|
||||
return s.RunCommand("git checkout -b " + name)
|
||||
}
|
||||
|
||||
func (s *Shell) Checkout(name string) *Shell {
|
||||
return s.RunCommand("git checkout " + name)
|
||||
}
|
||||
|
||||
func (s *Shell) GitAdd(path string) *Shell {
|
||||
return s.RunCommand(fmt.Sprintf("git add \"%s\"", path))
|
||||
}
|
||||
@ -67,6 +87,13 @@ func (s *Shell) CreateFileAndAdd(fileName string, fileContents string) *Shell {
|
||||
GitAdd(fileName)
|
||||
}
|
||||
|
||||
// convenience method for updating a file and adding it
|
||||
func (s *Shell) UpdateFileAndAdd(fileName string, fileContents string) *Shell {
|
||||
return s.
|
||||
UpdateFile(fileName, fileContents).
|
||||
GitAdd(fileName)
|
||||
}
|
||||
|
||||
// creates commits 01, 02, 03, ..., n with a new file in each
|
||||
// The reason for padding with zeroes is so that it's easier to do string
|
||||
// matches on the commit messages when there are many of them
|
||||
|
@ -174,7 +174,7 @@ func (self *Snapshotter) compareSnapshots() error {
|
||||
}
|
||||
self.logf("%s", string(bytes))
|
||||
|
||||
return errors.New(getDiff(f.Name(), actualRepo, expectedRepo))
|
||||
return errors.New(getDiff(f.Name(), expectedRepo, actualRepo))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ func (self *IntegrationTest) SetupRepo(shell *Shell) {
|
||||
|
||||
// I want access to all contexts, the model, the ability to press a key, the ability to log,
|
||||
func (self *IntegrationTest) Run(gui integrationTypes.GuiDriver) {
|
||||
shell := NewShell()
|
||||
shell := NewShell("/tmp/lazygit-test")
|
||||
assert := NewAssert(gui)
|
||||
keys := gui.Keys()
|
||||
input := NewInput(gui, keys, assert, KeyPressDelay())
|
||||
|
@ -56,6 +56,10 @@ func (self *fakeGuiDriver) SecondaryView() *gocui.View {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *fakeGuiDriver) View(viewName string) *gocui.View {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestAssertionFailure(t *testing.T) {
|
||||
test := NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: unitTestDescription,
|
||||
|
@ -4,6 +4,8 @@
|
||||
package deprecated
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@ -95,6 +97,15 @@ func runCmdHeadless(cmd *exec.Cmd) error {
|
||||
"TERM=xterm",
|
||||
)
|
||||
|
||||
// not writing stderr to the pty because we want to capture a panic if
|
||||
// there is one. But some commands will not be in tty mode if stderr is
|
||||
// not a terminal. We'll need to keep an eye out for that.
|
||||
stderr := new(bytes.Buffer)
|
||||
cmd.Stderr = stderr
|
||||
|
||||
// these rows and columns are ignored because internally we use tcell's
|
||||
// simulation screen. However we still need the pty for the sake of
|
||||
// running other commands in a pty.
|
||||
f, err := pty.StartWithSize(cmd, &pty.Winsize{Rows: 100, Cols: 100})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -102,5 +113,10 @@ func runCmdHeadless(cmd *exec.Cmd) error {
|
||||
|
||||
_, _ = io.Copy(ioutil.Discard, f)
|
||||
|
||||
if cmd.Wait() != nil {
|
||||
// return an error with the stderr output
|
||||
return errors.New(stderr.String())
|
||||
}
|
||||
|
||||
return f.Close()
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ func getTestSpeeds(testStartSpeed float64, mode Mode, speedStr string) []float64
|
||||
if startSpeed > 5 {
|
||||
speeds = append(speeds, 5)
|
||||
}
|
||||
speeds = append(speeds, 1, 1)
|
||||
speeds = append(speeds, 1, 0.5, 0.5)
|
||||
|
||||
return speeds
|
||||
}
|
||||
|
86
pkg/integration/tests/bisect/basic.go
Normal file
86
pkg/integration/tests/bisect/basic.go
Normal file
@ -0,0 +1,86 @@
|
||||
package bisect
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var Basic = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Start a git bisect to find a bad commit",
|
||||
ExtraCmdArgs: "",
|
||||
Skip: false,
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.
|
||||
CreateNCommits(10)
|
||||
},
|
||||
SetupConfig: func(cfg *config.AppConfig) {},
|
||||
Run: func(
|
||||
shell *Shell,
|
||||
input *Input,
|
||||
assert *Assert,
|
||||
keys config.KeybindingConfig,
|
||||
) {
|
||||
viewBisectOptions := func() {
|
||||
input.PressKeys(keys.Commits.ViewBisectOptions)
|
||||
assert.InMenu()
|
||||
}
|
||||
markCommitAsBad := func() {
|
||||
viewBisectOptions()
|
||||
assert.MatchSelectedLine(Contains("bad"))
|
||||
|
||||
input.Confirm()
|
||||
}
|
||||
|
||||
markCommitAsGood := func() {
|
||||
viewBisectOptions()
|
||||
assert.MatchSelectedLine(Contains("bad"))
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("good"))
|
||||
|
||||
input.Confirm()
|
||||
}
|
||||
|
||||
assert.AtLeastOneCommit()
|
||||
|
||||
input.SwitchToCommitsWindow()
|
||||
|
||||
assert.MatchSelectedLine(Contains("commit 10"))
|
||||
|
||||
input.NavigateToListItemContainingText("commit 09")
|
||||
|
||||
markCommitAsBad()
|
||||
|
||||
assert.MatchViewContent("information", Contains("bisecting"))
|
||||
|
||||
assert.CurrentViewName("commits")
|
||||
assert.MatchSelectedLine(Contains("<-- bad"))
|
||||
|
||||
input.NavigateToListItemContainingText("commit 02")
|
||||
|
||||
markCommitAsGood()
|
||||
|
||||
// lazygit will land us in the comit between our good and bad commits.
|
||||
assert.CurrentViewName("commits")
|
||||
assert.MatchSelectedLine(Contains("commit 05"))
|
||||
assert.MatchSelectedLine(Contains("<-- current"))
|
||||
|
||||
markCommitAsBad()
|
||||
|
||||
assert.CurrentViewName("commits")
|
||||
assert.MatchSelectedLine(Contains("commit 04"))
|
||||
assert.MatchSelectedLine(Contains("<-- current"))
|
||||
|
||||
markCommitAsGood()
|
||||
|
||||
assert.InAlert()
|
||||
assert.MatchCurrentViewContent(Contains("Bisect complete!"))
|
||||
// commit 5 is the culprit because we marked 4 as good and 5 as bad.
|
||||
assert.MatchCurrentViewContent(Contains("commit 05"))
|
||||
assert.MatchCurrentViewContent(Contains("Do you want to reset"))
|
||||
input.Confirm()
|
||||
|
||||
assert.CurrentViewName("commits")
|
||||
assert.MatchCurrentViewContent(Contains("commit 04"))
|
||||
assert.MatchViewContent("information", NotContains("bisecting"))
|
||||
},
|
||||
})
|
69
pkg/integration/tests/bisect/from_other_branch.go
Normal file
69
pkg/integration/tests/bisect/from_other_branch.go
Normal file
@ -0,0 +1,69 @@
|
||||
package bisect
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var FromOtherBranch = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Opening lazygit when bisect has been started from another branch. There's an issue where we don't reselect the current branch if we mark the current branch as bad so this test side-steps that problem",
|
||||
ExtraCmdArgs: "",
|
||||
Skip: false,
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.
|
||||
EmptyCommit("only commit on master"). // this'll ensure we have a master branch
|
||||
NewBranch("other").
|
||||
CreateNCommits(10).
|
||||
Checkout("master").
|
||||
RunCommand("git bisect start other~2 other~5")
|
||||
},
|
||||
SetupConfig: func(cfg *config.AppConfig) {},
|
||||
Run: func(
|
||||
shell *Shell,
|
||||
input *Input,
|
||||
assert *Assert,
|
||||
keys config.KeybindingConfig,
|
||||
) {
|
||||
viewBisectOptions := func() {
|
||||
input.PressKeys(keys.Commits.ViewBisectOptions)
|
||||
assert.InMenu()
|
||||
}
|
||||
|
||||
markCommitAsGood := func() {
|
||||
viewBisectOptions()
|
||||
assert.MatchSelectedLine(Contains("bad"))
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("good"))
|
||||
|
||||
input.Confirm()
|
||||
}
|
||||
|
||||
assert.MatchViewContent("information", Contains("bisecting"))
|
||||
|
||||
assert.AtLeastOneCommit()
|
||||
|
||||
input.SwitchToCommitsWindow()
|
||||
|
||||
assert.MatchSelectedLine(Contains("<-- bad"))
|
||||
assert.MatchSelectedLine(Contains("commit 08"))
|
||||
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("<-- current"))
|
||||
assert.MatchSelectedLine(Contains("commit 07"))
|
||||
|
||||
markCommitAsGood()
|
||||
|
||||
assert.InAlert()
|
||||
assert.MatchCurrentViewContent(Contains("Bisect complete!"))
|
||||
assert.MatchCurrentViewContent(Contains("commit 08"))
|
||||
assert.MatchCurrentViewContent(Contains("Do you want to reset"))
|
||||
input.Confirm()
|
||||
|
||||
assert.MatchViewContent("information", NotContains("bisecting"))
|
||||
|
||||
// back in master branch which just had the one commit
|
||||
assert.CurrentViewName("commits")
|
||||
assert.CommitCount(1)
|
||||
assert.MatchSelectedLine(Contains("only commit on master"))
|
||||
},
|
||||
})
|
40
pkg/integration/tests/branch/delete.go
Normal file
40
pkg/integration/tests/branch/delete.go
Normal file
@ -0,0 +1,40 @@
|
||||
package branch
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var Delete = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Try to delete the checked out branch first (to no avail), and then delete another branch.",
|
||||
ExtraCmdArgs: "",
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.
|
||||
EmptyCommit("blah").
|
||||
NewBranch("branch-one").
|
||||
NewBranch("branch-two")
|
||||
},
|
||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||
input.SwitchToBranchesWindow()
|
||||
assert.CurrentViewName("localBranches")
|
||||
|
||||
assert.MatchSelectedLine(Contains("branch-two"))
|
||||
input.PressKeys(keys.Universal.Remove)
|
||||
assert.InAlert()
|
||||
assert.MatchCurrentViewContent(Contains("You cannot delete the checked out branch!"))
|
||||
|
||||
input.Confirm()
|
||||
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("branch-one"))
|
||||
input.PressKeys(keys.Universal.Remove)
|
||||
assert.InConfirm()
|
||||
assert.MatchCurrentViewContent(Contains("Are you sure you want to delete the branch 'branch-one'?"))
|
||||
input.Confirm()
|
||||
assert.CurrentViewName("localBranches")
|
||||
assert.MatchSelectedLine(Contains("master"))
|
||||
assert.MatchCurrentViewContent(NotContains("branch-one"))
|
||||
},
|
||||
})
|
53
pkg/integration/tests/branch/rebase.go
Normal file
53
pkg/integration/tests/branch/rebase.go
Normal file
@ -0,0 +1,53 @@
|
||||
package branch
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/shared"
|
||||
)
|
||||
|
||||
var Rebase = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Rebase onto another branch, deal with the conflicts.",
|
||||
ExtraCmdArgs: "",
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shared.MergeConflictsSetup(shell)
|
||||
},
|
||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||
input.SwitchToBranchesWindow()
|
||||
assert.CurrentViewName("localBranches")
|
||||
|
||||
assert.MatchSelectedLine(Contains("first-change-branch"))
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("second-change-branch"))
|
||||
input.PressKeys(keys.Branches.RebaseBranch)
|
||||
|
||||
assert.InConfirm()
|
||||
assert.MatchCurrentViewContent(Contains("Are you sure you want to rebase 'first-change-branch' onto 'second-change-branch'?"))
|
||||
input.Confirm()
|
||||
|
||||
assert.InConfirm()
|
||||
assert.MatchCurrentViewContent(Contains("Conflicts!"))
|
||||
input.Confirm()
|
||||
|
||||
assert.CurrentViewName("files")
|
||||
assert.MatchSelectedLine(Contains("file"))
|
||||
|
||||
// not using Confirm() convenience method because I suspect we might change this
|
||||
// keybinding to something more bespoke
|
||||
input.PressKeys(keys.Universal.Confirm)
|
||||
|
||||
assert.CurrentViewName("mergeConflicts")
|
||||
input.PrimaryAction()
|
||||
|
||||
assert.MatchViewContent("information", Contains("rebasing"))
|
||||
assert.InConfirm()
|
||||
assert.MatchCurrentViewContent(Contains("all merge conflicts resolved. Continue?"))
|
||||
input.Confirm()
|
||||
assert.MatchViewContent("information", NotContains("rebasing"))
|
||||
|
||||
// this proves we actually have integrated the changes from second-change-branch
|
||||
assert.MatchViewContent("commits", Contains("second-change-branch unrelated change"))
|
||||
},
|
||||
})
|
69
pkg/integration/tests/branch/rebase_and_drop.go
Normal file
69
pkg/integration/tests/branch/rebase_and_drop.go
Normal file
@ -0,0 +1,69 @@
|
||||
package branch
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/shared"
|
||||
)
|
||||
|
||||
var RebaseAndDrop = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Rebase onto another branch, deal with the conflicts. Also mark a commit to be dropped before continuing.",
|
||||
ExtraCmdArgs: "",
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shared.MergeConflictsSetup(shell)
|
||||
// addin a couple additional commits so that we can drop one
|
||||
shell.EmptyCommit("to remove")
|
||||
shell.EmptyCommit("to keep")
|
||||
},
|
||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||
input.SwitchToBranchesWindow()
|
||||
assert.CurrentViewName("localBranches")
|
||||
|
||||
assert.MatchSelectedLine(Contains("first-change-branch"))
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("second-change-branch"))
|
||||
input.PressKeys(keys.Branches.RebaseBranch)
|
||||
|
||||
assert.InConfirm()
|
||||
assert.MatchCurrentViewContent(Contains("Are you sure you want to rebase 'first-change-branch' onto 'second-change-branch'?"))
|
||||
input.Confirm()
|
||||
|
||||
assert.MatchViewContent("information", Contains("rebasing"))
|
||||
|
||||
assert.InConfirm()
|
||||
assert.MatchCurrentViewContent(Contains("Conflicts!"))
|
||||
input.Confirm()
|
||||
|
||||
assert.CurrentViewName("files")
|
||||
assert.MatchSelectedLine(Contains("file"))
|
||||
|
||||
input.SwitchToCommitsWindow()
|
||||
assert.MatchSelectedLine(Contains("pick")) // this means it's a rebasing commit
|
||||
input.NextItem()
|
||||
input.PressKeys(keys.Universal.Remove)
|
||||
assert.MatchSelectedLine(Contains("to remove"))
|
||||
assert.MatchSelectedLine(Contains("drop"))
|
||||
|
||||
input.SwitchToFilesWindow()
|
||||
|
||||
// not using Confirm() convenience method because I suspect we might change this
|
||||
// keybinding to something more bespoke
|
||||
input.PressKeys(keys.Universal.Confirm)
|
||||
|
||||
assert.CurrentViewName("mergeConflicts")
|
||||
input.PrimaryAction()
|
||||
|
||||
assert.InConfirm()
|
||||
assert.MatchCurrentViewContent(Contains("all merge conflicts resolved. Continue?"))
|
||||
input.Confirm()
|
||||
|
||||
assert.MatchViewContent("information", NotContains("rebasing"))
|
||||
|
||||
// this proves we actually have integrated the changes from second-change-branch
|
||||
assert.MatchViewContent("commits", Contains("second-change-branch unrelated change"))
|
||||
assert.MatchViewContent("commits", Contains("to keep"))
|
||||
assert.MatchViewContent("commits", NotContains("to remove"))
|
||||
},
|
||||
})
|
@ -2,15 +2,15 @@ package branch
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var Suggestions = components.NewIntegrationTest(components.NewIntegrationTestArgs{
|
||||
var Suggestions = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Checking out a branch with name suggestions",
|
||||
ExtraCmdArgs: "",
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *components.Shell) {
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.
|
||||
EmptyCommit("my commit message").
|
||||
NewBranch("new-branch").
|
||||
@ -20,7 +20,7 @@ var Suggestions = components.NewIntegrationTest(components.NewIntegrationTestArg
|
||||
NewBranch("other-new-branch-2").
|
||||
NewBranch("other-new-branch-3")
|
||||
},
|
||||
Run: func(shell *components.Shell, input *components.Input, assert *components.Assert, keys config.KeybindingConfig) {
|
||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||
input.SwitchToBranchesWindow()
|
||||
assert.CurrentViewName("localBranches")
|
||||
|
||||
@ -34,6 +34,7 @@ var Suggestions = components.NewIntegrationTest(components.NewIntegrationTestArg
|
||||
|
||||
// we expect the first suggestion to be the branch we want because it most
|
||||
// closely matches what we typed in
|
||||
assert.MatchSelectedLine(Contains("branch-to-checkout"))
|
||||
input.Confirm()
|
||||
|
||||
assert.CurrentBranchName("branch-to-checkout")
|
||||
|
66
pkg/integration/tests/cherry_pick/cherry_pick.go
Normal file
66
pkg/integration/tests/cherry_pick/cherry_pick.go
Normal file
@ -0,0 +1,66 @@
|
||||
package cherry_pick
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var CherryPick = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Cherry pick commits from the subcommits view, without conflicts",
|
||||
ExtraCmdArgs: "",
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.
|
||||
EmptyCommit("base").
|
||||
NewBranch("first-branch").
|
||||
NewBranch("second-branch").
|
||||
Checkout("first-branch").
|
||||
EmptyCommit("one").
|
||||
EmptyCommit("two").
|
||||
Checkout("second-branch").
|
||||
EmptyCommit("three").
|
||||
EmptyCommit("four").
|
||||
Checkout("first-branch")
|
||||
},
|
||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||
input.SwitchToBranchesWindow()
|
||||
assert.CurrentViewName("localBranches")
|
||||
|
||||
assert.MatchSelectedLine(Contains("first-branch"))
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("second-branch"))
|
||||
|
||||
input.Enter()
|
||||
|
||||
assert.CurrentViewName("subCommits")
|
||||
assert.MatchSelectedLine(Contains("four"))
|
||||
input.PressKeys(keys.Commits.CherryPickCopy)
|
||||
assert.MatchViewContent("information", Contains("1 commit copied"))
|
||||
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("three"))
|
||||
input.PressKeys(keys.Commits.CherryPickCopy)
|
||||
assert.MatchViewContent("information", Contains("2 commits copied"))
|
||||
|
||||
input.SwitchToCommitsWindow()
|
||||
assert.CurrentViewName("commits")
|
||||
|
||||
assert.MatchSelectedLine(Contains("two"))
|
||||
input.PressKeys(keys.Commits.PasteCommits)
|
||||
assert.InAlert()
|
||||
assert.MatchCurrentViewContent(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?"))
|
||||
|
||||
input.Confirm()
|
||||
assert.CurrentViewName("commits")
|
||||
assert.MatchSelectedLine(Contains("four"))
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("three"))
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("two"))
|
||||
|
||||
assert.MatchViewContent("information", Contains("2 commits copied"))
|
||||
input.PressKeys(keys.Universal.Return)
|
||||
assert.MatchViewContent("information", NotContains("commits copied"))
|
||||
},
|
||||
})
|
87
pkg/integration/tests/cherry_pick/cherry_pick_conflicts.go
Normal file
87
pkg/integration/tests/cherry_pick/cherry_pick_conflicts.go
Normal file
@ -0,0 +1,87 @@
|
||||
package cherry_pick
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/shared"
|
||||
)
|
||||
|
||||
var CherryPickConflicts = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Cherry pick commits from the subcommits view, with conflicts",
|
||||
ExtraCmdArgs: "",
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shared.MergeConflictsSetup(shell)
|
||||
},
|
||||
Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
|
||||
input.SwitchToBranchesWindow()
|
||||
assert.CurrentViewName("localBranches")
|
||||
|
||||
assert.MatchSelectedLine(Contains("first-change-branch"))
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("second-change-branch"))
|
||||
|
||||
input.Enter()
|
||||
|
||||
assert.CurrentViewName("subCommits")
|
||||
assert.MatchSelectedLine(Contains("second-change-branch unrelated change"))
|
||||
input.PressKeys(keys.Commits.CherryPickCopy)
|
||||
assert.MatchViewContent("information", Contains("1 commit copied"))
|
||||
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("second change"))
|
||||
input.PressKeys(keys.Commits.CherryPickCopy)
|
||||
assert.MatchViewContent("information", Contains("2 commits copied"))
|
||||
|
||||
input.SwitchToCommitsWindow()
|
||||
assert.CurrentViewName("commits")
|
||||
|
||||
assert.MatchSelectedLine(Contains("first change"))
|
||||
input.PressKeys(keys.Commits.PasteCommits)
|
||||
assert.InAlert()
|
||||
assert.MatchCurrentViewContent(Contains("Are you sure you want to cherry-pick the copied commits onto this branch?"))
|
||||
|
||||
input.Confirm()
|
||||
|
||||
assert.MatchCurrentViewContent(Contains("Conflicts!"))
|
||||
input.Confirm()
|
||||
|
||||
assert.CurrentViewName("files")
|
||||
assert.MatchSelectedLine(Contains("file"))
|
||||
|
||||
// not using Confirm() convenience method because I suspect we might change this
|
||||
// keybinding to something more bespoke
|
||||
input.PressKeys(keys.Universal.Confirm)
|
||||
|
||||
assert.CurrentViewName("mergeConflicts")
|
||||
// picking 'Second change'
|
||||
input.NextItem()
|
||||
input.PrimaryAction()
|
||||
|
||||
assert.InConfirm()
|
||||
assert.MatchCurrentViewContent(Contains("all merge conflicts resolved. Continue?"))
|
||||
input.Confirm()
|
||||
|
||||
assert.CurrentViewName("files")
|
||||
assert.WorkingTreeFileCount(0)
|
||||
|
||||
input.SwitchToCommitsWindow()
|
||||
assert.CurrentViewName("commits")
|
||||
|
||||
assert.MatchSelectedLine(Contains("second-change-branch unrelated change"))
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("second change"))
|
||||
// because we picked 'Second change' when resolving the conflict,
|
||||
// we now see this commit as having replaced First Change with Second Change,
|
||||
// as opposed to replacing 'Original' with 'Second change'
|
||||
assert.MatchMainViewContent(Contains("-First Change"))
|
||||
assert.MatchMainViewContent(Contains("+Second Change"))
|
||||
input.NextItem()
|
||||
assert.MatchSelectedLine(Contains("first change"))
|
||||
|
||||
assert.MatchViewContent("information", Contains("2 commits copied"))
|
||||
input.PressKeys(keys.Universal.Return)
|
||||
assert.MatchViewContent("information", NotContains("commits copied"))
|
||||
},
|
||||
})
|
1
pkg/integration/tests/shared/README.md
Normal file
1
pkg/integration/tests/shared/README.md
Normal file
@ -0,0 +1 @@
|
||||
This package contains shared helper functions for tests. It is not intended to contain any actual tests itself.
|
49
pkg/integration/tests/shared/conflicts.go
Normal file
49
pkg/integration/tests/shared/conflicts.go
Normal file
@ -0,0 +1,49 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var OriginalFileContent = `
|
||||
This
|
||||
Is
|
||||
The
|
||||
Original
|
||||
File
|
||||
`
|
||||
|
||||
var FirstChangeFileContent = `
|
||||
This
|
||||
Is
|
||||
The
|
||||
First Change
|
||||
File
|
||||
`
|
||||
|
||||
var SecondChangeFileContent = `
|
||||
This
|
||||
Is
|
||||
The
|
||||
Second Change
|
||||
File
|
||||
`
|
||||
|
||||
// prepares us for a rebase/merge that has conflicts
|
||||
var MergeConflictsSetup = func(shell *Shell) {
|
||||
shell.
|
||||
NewBranch("original-branch").
|
||||
EmptyCommit("one").
|
||||
EmptyCommit("two").
|
||||
EmptyCommit("three").
|
||||
CreateFileAndAdd("file", OriginalFileContent).
|
||||
Commit("original").
|
||||
NewBranch("first-change-branch").
|
||||
UpdateFileAndAdd("file", FirstChangeFileContent).
|
||||
Commit("first change").
|
||||
Checkout("original-branch").
|
||||
NewBranch("second-change-branch").
|
||||
UpdateFileAndAdd("file", SecondChangeFileContent).
|
||||
Commit("second change").
|
||||
EmptyCommit("second-change-branch unrelated change").
|
||||
Checkout("first-change-branch")
|
||||
}
|
@ -9,7 +9,9 @@ import (
|
||||
"github.com/jesseduffield/generics/set"
|
||||
"github.com/jesseduffield/generics/slices"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/bisect"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/branch"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/cherry_pick"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/commit"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/custom_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/interactive_rebase"
|
||||
@ -23,10 +25,17 @@ var tests = []*components.IntegrationTest{
|
||||
commit.Commit,
|
||||
commit.NewBranch,
|
||||
branch.Suggestions,
|
||||
branch.Delete,
|
||||
branch.Rebase,
|
||||
branch.RebaseAndDrop,
|
||||
interactive_rebase.One,
|
||||
custom_commands.Basic,
|
||||
custom_commands.MultiplePrompts,
|
||||
custom_commands.MenuFromCommand,
|
||||
bisect.Basic,
|
||||
bisect.FromOtherBranch,
|
||||
cherry_pick.CherryPick,
|
||||
cherry_pick.CherryPickConflicts,
|
||||
}
|
||||
|
||||
func GetTests() []*components.IntegrationTest {
|
||||
@ -49,6 +58,11 @@ func GetTests() []*components.IntegrationTest {
|
||||
return nil
|
||||
}
|
||||
|
||||
// the shared directory won't itself contain tests: only shared helper functions
|
||||
if filepath.Base(filepath.Dir(path)) == "shared" {
|
||||
return nil
|
||||
}
|
||||
|
||||
nameFromPath := components.TestNameFromFilePath(path)
|
||||
if !testNamesSet.Includes(nameFromPath) {
|
||||
missingTestNames = append(missingTestNames, nameFromPath)
|
||||
|
@ -34,4 +34,5 @@ type GuiDriver interface {
|
||||
// the other view that sometimes appears to the right of the side panel
|
||||
// e.g. when we're showing both staged and unstaged changes
|
||||
SecondaryView() *gocui.View
|
||||
View(viewName string) *gocui.View
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
e927f0f9467e772eea36f24053c9b534303b106a
|
@ -1,16 +0,0 @@
|
||||
git bisect start
|
||||
# bad: [054bdf969fdcf1f90f1998666f628d40f72fde4f] commit 19
|
||||
git bisect bad 054bdf969fdcf1f90f1998666f628d40f72fde4f
|
||||
# good: [39983ea412adebe6c5a3d4451a7673cf0962c472] commit 9
|
||||
git bisect good 39983ea412adebe6c5a3d4451a7673cf0962c472
|
||||
# good: [e9d2f825e793bc9ac2be698348dbe669bad34cad] commit 14
|
||||
git bisect good e9d2f825e793bc9ac2be698348dbe669bad34cad
|
||||
# skip: [d1f7a85555fe6f10dd44754d35459ae741cb107c] commit 15
|
||||
git bisect skip d1f7a85555fe6f10dd44754d35459ae741cb107c
|
||||
# skip: [bc21c8fabc28201fab6c60503168ecda25ad8626] commit 17
|
||||
git bisect skip bc21c8fabc28201fab6c60503168ecda25ad8626
|
||||
# good: [67fbfb3b74c2381ad1e058949231f2b4f0c8921f] commit 16
|
||||
git bisect good 67fbfb3b74c2381ad1e058949231f2b4f0c8921f
|
||||
# good: [e927f0f9467e772eea36f24053c9b534303b106a] commit 18
|
||||
git bisect good e927f0f9467e772eea36f24053c9b534303b106a
|
||||
# first bad commit: [054bdf969fdcf1f90f1998666f628d40f72fde4f] commit 19
|
@ -1 +0,0 @@
|
||||
master
|
@ -1,2 +0,0 @@
|
||||
bad
|
||||
good
|
@ -1 +0,0 @@
|
||||
commit 20
|
@ -1 +0,0 @@
|
||||
ref: refs/heads/test
|
Binary file not shown.
@ -1,24 +0,0 @@
|
||||
0000000000000000000000000000000000000000 005ca78c7fb8157683fa61158235b250d2316004 CI <CI@example.com> 1643185278 +1100 commit (initial): commit 1
|
||||
005ca78c7fb8157683fa61158235b250d2316004 d9328d9b2c9536fdf01641dd03f4a254d2c86601 CI <CI@example.com> 1643185278 +1100 commit: commit 2
|
||||
d9328d9b2c9536fdf01641dd03f4a254d2c86601 e59bbaffe94b06acaadab4245f30ff3e11c66e5b CI <CI@example.com> 1643185278 +1100 commit: commit 3
|
||||
e59bbaffe94b06acaadab4245f30ff3e11c66e5b 32e7b0308424a817ed5aa5bba94b06b72a1b8ce5 CI <CI@example.com> 1643185278 +1100 commit: commit 4
|
||||
32e7b0308424a817ed5aa5bba94b06b72a1b8ce5 96202a92c1d3bde1b20d6f3dec8e742d09732b4d CI <CI@example.com> 1643185278 +1100 commit: commit 5
|
||||
96202a92c1d3bde1b20d6f3dec8e742d09732b4d 82d721eb037f7045056023d0904989781ce1f526 CI <CI@example.com> 1643185278 +1100 commit: commit 6
|
||||
82d721eb037f7045056023d0904989781ce1f526 b97844c9437a4ab69c8165cadd97bc597b43135b CI <CI@example.com> 1643185278 +1100 commit: commit 7
|
||||
b97844c9437a4ab69c8165cadd97bc597b43135b ebe59a71e9750e75fb983f241687cdf7f0c8ce94 CI <CI@example.com> 1643185278 +1100 commit: commit 8
|
||||
ebe59a71e9750e75fb983f241687cdf7f0c8ce94 39983ea412adebe6c5a3d4451a7673cf0962c472 CI <CI@example.com> 1643185278 +1100 commit: commit 9
|
||||
39983ea412adebe6c5a3d4451a7673cf0962c472 dbb21289ee21b2ff0f3de2bc7d00038b30c4e353 CI <CI@example.com> 1643185278 +1100 commit: commit 10
|
||||
dbb21289ee21b2ff0f3de2bc7d00038b30c4e353 5f9397e5bcee1ac2a3fe6d834d42e36b74ef4ca8 CI <CI@example.com> 1643185278 +1100 commit: commit 11
|
||||
5f9397e5bcee1ac2a3fe6d834d42e36b74ef4ca8 267465454f74736bbe5b493c7f69dd3d024e26e5 CI <CI@example.com> 1643185278 +1100 commit: commit 12
|
||||
267465454f74736bbe5b493c7f69dd3d024e26e5 478a007451b33c7a234c60f0d13b164561b29094 CI <CI@example.com> 1643185278 +1100 commit: commit 13
|
||||
478a007451b33c7a234c60f0d13b164561b29094 e9d2f825e793bc9ac2be698348dbe669bad34cad CI <CI@example.com> 1643185278 +1100 commit: commit 14
|
||||
e9d2f825e793bc9ac2be698348dbe669bad34cad d1f7a85555fe6f10dd44754d35459ae741cb107c CI <CI@example.com> 1643185278 +1100 commit: commit 15
|
||||
d1f7a85555fe6f10dd44754d35459ae741cb107c 67fbfb3b74c2381ad1e058949231f2b4f0c8921f CI <CI@example.com> 1643185278 +1100 commit: commit 16
|
||||
67fbfb3b74c2381ad1e058949231f2b4f0c8921f bc21c8fabc28201fab6c60503168ecda25ad8626 CI <CI@example.com> 1643185278 +1100 commit: commit 17
|
||||
bc21c8fabc28201fab6c60503168ecda25ad8626 e927f0f9467e772eea36f24053c9b534303b106a CI <CI@example.com> 1643185278 +1100 commit: commit 18
|
||||
e927f0f9467e772eea36f24053c9b534303b106a 054bdf969fdcf1f90f1998666f628d40f72fde4f CI <CI@example.com> 1643185278 +1100 commit: commit 19
|
||||
054bdf969fdcf1f90f1998666f628d40f72fde4f 78d41b2abbd2f52c1ebf2f496268a915d59eb27b CI <CI@example.com> 1643185278 +1100 commit: commit 20
|
||||
78d41b2abbd2f52c1ebf2f496268a915d59eb27b e9d2f825e793bc9ac2be698348dbe669bad34cad CI <CI@example.com> 1643185283 +1100 checkout: moving from master to e9d2f825e793bc9ac2be698348dbe669bad34cad
|
||||
e9d2f825e793bc9ac2be698348dbe669bad34cad 67fbfb3b74c2381ad1e058949231f2b4f0c8921f CI <CI@example.com> 1643185286 +1100 checkout: moving from e9d2f825e793bc9ac2be698348dbe669bad34cad to 67fbfb3b74c2381ad1e058949231f2b4f0c8921f
|
||||
67fbfb3b74c2381ad1e058949231f2b4f0c8921f e927f0f9467e772eea36f24053c9b534303b106a CI <CI@example.com> 1643185295 +1100 checkout: moving from 67fbfb3b74c2381ad1e058949231f2b4f0c8921f to e927f0f9467e772eea36f24053c9b534303b106a
|
||||
e927f0f9467e772eea36f24053c9b534303b106a 78d41b2abbd2f52c1ebf2f496268a915d59eb27b CI <CI@example.com> 1643185301 +1100 checkout: moving from e927f0f9467e772eea36f24053c9b534303b106a to test
|
@ -1,20 +0,0 @@
|
||||
0000000000000000000000000000000000000000 005ca78c7fb8157683fa61158235b250d2316004 CI <CI@example.com> 1643185278 +1100 commit (initial): commit 1
|
||||
005ca78c7fb8157683fa61158235b250d2316004 d9328d9b2c9536fdf01641dd03f4a254d2c86601 CI <CI@example.com> 1643185278 +1100 commit: commit 2
|
||||
d9328d9b2c9536fdf01641dd03f4a254d2c86601 e59bbaffe94b06acaadab4245f30ff3e11c66e5b CI <CI@example.com> 1643185278 +1100 commit: commit 3
|
||||
e59bbaffe94b06acaadab4245f30ff3e11c66e5b 32e7b0308424a817ed5aa5bba94b06b72a1b8ce5 CI <CI@example.com> 1643185278 +1100 commit: commit 4
|
||||
32e7b0308424a817ed5aa5bba94b06b72a1b8ce5 96202a92c1d3bde1b20d6f3dec8e742d09732b4d CI <CI@example.com> 1643185278 +1100 commit: commit 5
|
||||
96202a92c1d3bde1b20d6f3dec8e742d09732b4d 82d721eb037f7045056023d0904989781ce1f526 CI <CI@example.com> 1643185278 +1100 commit: commit 6
|
||||
82d721eb037f7045056023d0904989781ce1f526 b97844c9437a4ab69c8165cadd97bc597b43135b CI <CI@example.com> 1643185278 +1100 commit: commit 7
|
||||
b97844c9437a4ab69c8165cadd97bc597b43135b ebe59a71e9750e75fb983f241687cdf7f0c8ce94 CI <CI@example.com> 1643185278 +1100 commit: commit 8
|
||||
ebe59a71e9750e75fb983f241687cdf7f0c8ce94 39983ea412adebe6c5a3d4451a7673cf0962c472 CI <CI@example.com> 1643185278 +1100 commit: commit 9
|
||||
39983ea412adebe6c5a3d4451a7673cf0962c472 dbb21289ee21b2ff0f3de2bc7d00038b30c4e353 CI <CI@example.com> 1643185278 +1100 commit: commit 10
|
||||
dbb21289ee21b2ff0f3de2bc7d00038b30c4e353 5f9397e5bcee1ac2a3fe6d834d42e36b74ef4ca8 CI <CI@example.com> 1643185278 +1100 commit: commit 11
|
||||
5f9397e5bcee1ac2a3fe6d834d42e36b74ef4ca8 267465454f74736bbe5b493c7f69dd3d024e26e5 CI <CI@example.com> 1643185278 +1100 commit: commit 12
|
||||
267465454f74736bbe5b493c7f69dd3d024e26e5 478a007451b33c7a234c60f0d13b164561b29094 CI <CI@example.com> 1643185278 +1100 commit: commit 13
|
||||
478a007451b33c7a234c60f0d13b164561b29094 e9d2f825e793bc9ac2be698348dbe669bad34cad CI <CI@example.com> 1643185278 +1100 commit: commit 14
|
||||
e9d2f825e793bc9ac2be698348dbe669bad34cad d1f7a85555fe6f10dd44754d35459ae741cb107c CI <CI@example.com> 1643185278 +1100 commit: commit 15
|
||||
d1f7a85555fe6f10dd44754d35459ae741cb107c 67fbfb3b74c2381ad1e058949231f2b4f0c8921f CI <CI@example.com> 1643185278 +1100 commit: commit 16
|
||||
67fbfb3b74c2381ad1e058949231f2b4f0c8921f bc21c8fabc28201fab6c60503168ecda25ad8626 CI <CI@example.com> 1643185278 +1100 commit: commit 17
|
||||
bc21c8fabc28201fab6c60503168ecda25ad8626 e927f0f9467e772eea36f24053c9b534303b106a CI <CI@example.com> 1643185278 +1100 commit: commit 18
|
||||
e927f0f9467e772eea36f24053c9b534303b106a 054bdf969fdcf1f90f1998666f628d40f72fde4f CI <CI@example.com> 1643185278 +1100 commit: commit 19
|
||||
054bdf969fdcf1f90f1998666f628d40f72fde4f 78d41b2abbd2f52c1ebf2f496268a915d59eb27b CI <CI@example.com> 1643185278 +1100 commit: commit 20
|
@ -1 +0,0 @@
|
||||
0000000000000000000000000000000000000000 78d41b2abbd2f52c1ebf2f496268a915d59eb27b CI <CI@example.com> 1643185301 +1100 branch: Created from master
|
Binary file not shown.
Binary file not shown.
@ -1,2 +0,0 @@
|
||||
x��K
|
||||
1D]罤?ù‚ˆ0«9FÌtP0Î0Dðøfá¤vÅ{PUÖÖ(ùCßU!‘ø*äÔ%Çh¥’-KÁ…caŒšG–@fË»¾:hâP±&냆ÀªyølÑII7'VPn„>›üî÷u‡i†ó4_õ“ÛöÔSYÛÈ[¡è8D8!šÑŽQ]ÿÄü8a¾©:E
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,2 +0,0 @@
|
||||
x�ÎM
|
||||
1†a×=Eö‚4ý™$ "ÌjŽÑÖëC�oÀíÇÃÇ[ÖÖPâ¡ïªàÕº¢b}àê=OèXsvB.b¬“'fF6[ÚõÕA³FI„*Ò Â¾º€S¹Uª¶ðø&½û}Ýa^à</Wý¤¶=õTÖvœ‚GŽŽŽˆÖš±Ž¨®òŸ1_¥Á9ä
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
x+)JMU06b040031QHֻּIe�כ6פLסQ»תא)�¥¹:‹ױ�<…נפ
|
Binary file not shown.
@ -1,2 +0,0 @@
|
||||
x�ÎA
|
||||
1@Q×=Eö‚4m'm@D˜•Çh›ëC�ï,<€ÛÏ[üºôþ€L‡±µ¡Ð$DÕ&®”ŠfbQuKÕEïcçÍš·ö`§PD™X¥**[EæDDJ.I°�Jjò{Ü—
æœçÛµ}r_ŸíT—~¤à1M.&8"ZköºO�ö'ÿypÖ|à;’
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
x+)JMU06b040031QHклIeь▒■ЦС_ц3и[}ШY╝Кзbf┘k░
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,4 +0,0 @@
|
||||
x�ÎM
|
||||
Â@†a×sŠì™LÒ¤¡«#ó#
|
||||
Ž-e�ï,<€Û—‡�/µ>à$‡¶—
|
||||
K¡DšÑ˜,HœüdÔcÊ!O*ªIÝf{y5`Í{å#QRÄIüÍg¤ˆÂƒ`}€�½Û}Ýa^à</×ò±º=Ë)õÝŽCÐŽˆÞ»^û©Vþä?Èî{ò9
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user