From 3ea81d4a6f8e9144b5896112a517ddf5c27373a2 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Mon, 7 Aug 2023 10:53:31 +1000 Subject: [PATCH 1/3] Add undo demo --- README.md | 15 +++++++++++++++ docs/Undoing.md | 6 +++--- pkg/integration/tests/demo/undo.go | 18 +----------------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index c6da3a2e1..0eddae062 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,21 @@ Learn more in the [Rebase magic Youtube tutorial](https://youtu.be/4XaToVut_hs). ![custom_patch](../assets/demo/custom_patch-compressed.gif) +### Undo + +You can undo the last action by pressing 'z' and redo with `ctrl+z`. Here we drop a couple of commits and then undo the actions. +Undo uses the reflog which is specific to commits and branches so we can't undo changes to the working tree or stash. + +[More info](/docs/Undoing.md) + +![undo](../assets/demo/undo-compressed.gif) + +### Commit graph + +When viewing the commit graph in an enlarged window (use `+` and `_` to cycle window sizes), the commit graph is shown. Colours correspond to the commit authors, and as you navigate down the graph, the parent commits of the selected commit are highlighted. + +![commit_graph](../assets/demo/commit_graph-compressed.gif) + ## Tutorials [](https://youtu.be/CPLdltN7wgE) diff --git a/docs/Undoing.md b/docs/Undoing.md index 7b5a15648..0a4c2f381 100644 --- a/docs/Undoing.md +++ b/docs/Undoing.md @@ -1,9 +1,9 @@ # Undo/Redo in lazygit -![Gif](../../assets/undo2.gif) +You can undo the last action by pressing 'z' and redo with `ctrl+z`. Here we drop a couple of commits and then undo the actions. +Undo uses the reflog which is specific to commits and branches so we can't undo changes to the working tree or stash. -## Keybindings: -'z' to undo, 'ctrl+z' to redo +![undo](../../assets/demo/undo-compressed.gif) ## How it works diff --git a/pkg/integration/tests/demo/undo.go b/pkg/integration/tests/demo/undo.go index d6dbb0e83..725090ed6 100644 --- a/pkg/integration/tests/demo/undo.go +++ b/pkg/integration/tests/demo/undo.go @@ -5,8 +5,6 @@ import ( . "github.com/jesseduffield/lazygit/pkg/integration/components" ) -// TODO: fix confirmation view wrapping issue: https://github.com/jesseduffield/lazygit/issues/2872 - var Undo = NewIntegrationTest(NewIntegrationTestArgs{ Description: "Undo", ExtraCmdArgs: []string{}, @@ -38,14 +36,6 @@ var Undo = NewIntegrationTest(NewIntegrationTestArgs{ Confirm() } - confirmRedo := func() { - t.ExpectPopup().Confirmation(). - Title(Equals("Redo")). - Content(MatchesRegexp(`Are you sure you want to hard reset to '.*'\? An auto-stash will be performed if necessary\.`)). - Wait(500). - Confirm() - } - t.Views().Commits().Focus(). SetCaptionPrefix("Drop two commits"). Wait(1000). @@ -58,12 +48,6 @@ var Undo = NewIntegrationTest(NewIntegrationTestArgs{ Press(keys.Universal.Undo). Tap(confirmUndo). Press(keys.Universal.Undo). - Tap(confirmUndo). - SetCaptionPrefix("Redo the drops"). - Wait(1000). - Press(keys.Universal.Redo). - Tap(confirmRedo). - Press(keys.Universal.Redo). - Tap(confirmRedo) + Tap(confirmUndo) }, }) From f1753f36c828663951ffa2649be593ef4290ac40 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 12 Aug 2023 13:17:01 +1000 Subject: [PATCH 2/3] Add rebase from marked base commit test This also fixes a bug where after the rebase each commit in the commits view had a tick against it because we hadn't refreshed the view since the base commit was no longer marked --- README.md | 6 + .../helpers/merge_and_rebase_helper.go | 6 +- pkg/integration/components/random.go | 262 ++++++++++++++++++ pkg/integration/components/shell.go | 19 ++ .../tests/branch/rebase_from_marked_base.go | 24 +- pkg/integration/tests/demo/rebase_onto.go | 81 ++++++ pkg/integration/tests/test_list.go | 1 + 7 files changed, 385 insertions(+), 14 deletions(-) create mode 100644 pkg/integration/tests/demo/rebase_onto.go diff --git a/README.md b/README.md index 0eddae062..7ebffb36b 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,12 @@ Learn more in the [Rebase magic Youtube tutorial](https://youtu.be/4XaToVut_hs). ![custom_patch](../assets/demo/custom_patch-compressed.gif) +### Rebase from marked base commit + +Say you're on a feature branch that was itself branched off of the develop branch, and you've decided you'd rather be branching off the master branch. You need a way to rebase only the commits from your feature branch. In this demo we check to see which was the last commit on the develop branch, then press `shift+b` to mark that commit as our base commit, then press `r` on the master branch to rebase onto it, only bringing across the commits from our feature branch. Then we push our changes with `shift+p`. + +![rebase_onto](../assets/demo/rebase_onto-compressed.gif) + ### Undo You can undo the last action by pressing 'z' and redo with `ctrl+z`. Here we drop a couple of commits and then undo the actions. diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index db3ffa9ae..4c7b087aa 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -235,7 +235,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error { } err = self.CheckMergeOrRebase(err) if err == nil { - self.c.Modes().MarkedBaseCommit.Reset() + return self.ResetMarkedBaseCommit() } return err }) @@ -257,7 +257,9 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error { if err = self.CheckMergeOrRebase(err); err != nil { return err } - self.c.Modes().MarkedBaseCommit.Reset() + if err = self.ResetMarkedBaseCommit(); err != nil { + return err + } return self.c.PushContext(self.c.Contexts().LocalCommits) }, }, diff --git a/pkg/integration/components/random.go b/pkg/integration/components/random.go index cfd9d40ba..808089e23 100644 --- a/pkg/integration/components/random.go +++ b/pkg/integration/components/random.go @@ -210,3 +210,265 @@ var RandomFiles = []RandomFile{ {Name: `seo/alt_text2.go`, Content: `package seo`}, {Name: `moderation/comment_moderation2.go`, Content: `package moderation`}, } + +var RandomFileContents = []string{ + `package main + +import ( + "bytes" + "fmt" + "go/format" + "io/fs" + "os" + "strings" + + "github.com/samber/lo" +) + +func main() { + code := generateCode() + + formattedCode, err := format.Source(code) + if err != nil { + panic(err) + } + if err := os.WriteFile("test_list.go", formattedCode, 0o644); err != nil { + panic(err) + } +} +`, + ` +package tests + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/jesseduffield/generics/set" + "github.com/jesseduffield/lazycore/pkg/utils" + "github.com/jesseduffield/lazygit/pkg/integration/components" + "github.com/samber/lo" +) + +func GetTests() []*components.IntegrationTest { + // first we ensure that each test in this directory has actually been added to the above list. + testCount := 0 + + testNamesSet := set.NewFromSlice(lo.Map( + tests, + func(test *components.IntegrationTest, _ int) string { + return test.Name() + }, + )) +} +`, + ` +package components + +import ( + "os" + "strconv" + "strings" + + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" + "github.com/jesseduffield/lazygit/pkg/config" + integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types" + "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" +) + +// IntegrationTest describes an integration test that will be run against the lazygit gui. + +// our unit tests will use this description to avoid a panic caused by attempting +// to get the test's name via it's file's path. +const unitTestDescription = "test test" + +const ( + defaultWidth = 100 + defaultHeight = 100 +) +`, + `package components + +import ( + "fmt" + "time" + + "github.com/atotto/clipboard" + "github.com/jesseduffield/lazygit/pkg/config" + integrationTypes "github.com/jesseduffield/lazygit/pkg/integration/types" +) + +type TestDriver struct { + gui integrationTypes.GuiDriver + keys config.KeybindingConfig + inputDelay int + *assertionHelper + shell *Shell +} + +func NewTestDriver(gui integrationTypes.GuiDriver, shell *Shell, keys config.KeybindingConfig, inputDelay int) *TestDriver { + return &TestDriver{ + gui: gui, + keys: keys, + inputDelay: inputDelay, + assertionHelper: &assertionHelper{gui: gui}, + shell: shell, + } +} + +// key is something like 'w' or ''. It's best not to pass a direct value, +// but instead to go through the default user config to get a more meaningful key name +func (self *TestDriver) press(keyStr string) { + self.SetCaption(fmt.Sprintf("Pressing %s", keyStr)) + self.gui.PressKey(keyStr) + self.Wait(self.inputDelay) +} +`, + `package updates + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "runtime" + "strings" + "time" + + "github.com/go-errors/errors" + + "github.com/kardianos/osext" + + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/common" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/constants" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +// Updater checks for updates and does updates +type Updater struct { + *common.Common + Config config.AppConfigurer + OSCommand *oscommands.OSCommand +} + +// Updaterer implements the check and update methods +type Updaterer interface { + CheckForNewUpdate() + Update() +} +`, + ` +package utils + +import ( + "fmt" + "regexp" + "strings" +) + +// IsValidEmail checks if an email address is valid +func IsValidEmail(email string) bool { + // Using a regex pattern to validate email addresses + // This is a simple example and might not cover all edge cases + emailPattern := ` + "`" + `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$` + "`" + ` + match, _ := regexp.MatchString(emailPattern, email) + return match +} +`, + ` +package main + +import ( + "fmt" + "net/http" + "time" + + "github.com/jesseduffield/lazygit/pkg/utils" +) + +func main() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello, the current time is: %s", time.Now().Format(time.RFC3339)) + }) + + port := 8080 + utils.PrintMessage(fmt.Sprintf("Server is listening on port %d", port)) + http.ListenAndServe(fmt.Sprintf(":%d", port), nil) +} +`, + ` +package logging + +import ( + "fmt" + "os" + "time" +) + +// LogMessage represents a log message with its timestamp +type LogMessage struct { + Timestamp time.Time + Message string +} + +// Log writes a message to the log file along with a timestamp +func Log(message string) { + logFile, err := os.OpenFile("app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + fmt.Println("Error opening log file:", err) + return + } + defer logFile.Close() + + logEntry := LogMessage{ + Timestamp: time.Now(), + Message: message, + } + + logLine := fmt.Sprintf("[%s] %s\n", logEntry.Timestamp.Format("2006-01-02 15:04:05"), logEntry.Message) + _, err = logFile.WriteString(logLine) + if err != nil { + fmt.Println("Error writing to log file:", err) + } +} +`, + ` +package encryption + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "errors" + "io" +) + +// Encrypt encrypts a plaintext using AES-GCM encryption +func Encrypt(key []byte, plaintext []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + aesGCM, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonce := make([]byte, aesGCM.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return nil, err + } + + ciphertext := aesGCM.Seal(nil, nonce, plaintext, nil) + return append(nonce, ciphertext...), nil +} +`, +} diff --git a/pkg/integration/components/shell.go b/pkg/integration/components/shell.go index 4ba1bff67..4cf0990d6 100644 --- a/pkg/integration/components/shell.go +++ b/pkg/integration/components/shell.go @@ -18,6 +18,8 @@ type Shell struct { // when running the shell outside the gui we can directly panic on failure, // but inside the gui we need to close the gui before panicking fail func(string) + + randomFileContentIndex int } func NewShell(dir string, fail func(string)) *Shell { @@ -221,6 +223,16 @@ func (self *Shell) CreateNCommitsWithRandomMessages(n int) *Shell { return self } +// Creates a commit with a random file +// Only to be used in demos +func (self *Shell) RandomChangeCommit(message string) *Shell { + index := self.randomFileContentIndex + self.randomFileContentIndex++ + randomFileName := fmt.Sprintf("random-%d.go", index) + self.CreateFileAndAdd(randomFileName, RandomFileContents[index%len(RandomFileContents)]) + return self.Commit(message) +} + func (self *Shell) SetConfig(key string, value string) *Shell { self.RunCommand([]string{"git", "config", "--local", key, value}) return self @@ -361,3 +373,10 @@ func (self *Shell) Chdir(path string) *Shell { return self } + +func (self *Shell) SetAuthor(authorName string, authorEmail string) *Shell { + self.RunCommand([]string{"git", "config", "--local", "user.name", authorName}) + self.RunCommand([]string{"git", "config", "--local", "user.email", authorEmail}) + + return self +} diff --git a/pkg/integration/tests/branch/rebase_from_marked_base.go b/pkg/integration/tests/branch/rebase_from_marked_base.go index fb6ede722..c2ee307e3 100644 --- a/pkg/integration/tests/branch/rebase_from_marked_base.go +++ b/pkg/integration/tests/branch/rebase_from_marked_base.go @@ -40,12 +40,12 @@ var RebaseFromMarkedBase = NewIntegrationTest(NewIntegrationTestArgs{ NavigateToLine(Contains("active one")). Press(keys.Commits.MarkCommitAsBaseForRebase). Lines( - Contains("active three"), - Contains("active two"), + Contains("active three").Contains("✓"), + Contains("active two").Contains("✓"), Contains("↑↑↑ Will rebase from here ↑↑↑ active one"), - Contains("three"), - Contains("two"), - Contains("one"), + Contains("three").DoesNotContain("✓"), + Contains("two").DoesNotContain("✓"), + Contains("one").DoesNotContain("✓"), ) t.Views().Information().Content(Contains("Marked a base commit for rebase")) @@ -66,13 +66,13 @@ var RebaseFromMarkedBase = NewIntegrationTest(NewIntegrationTestArgs{ Confirm() t.Views().Commits().Lines( - Contains("active three"), - Contains("active two"), - Contains("target two"), - Contains("target one"), - Contains("three"), - Contains("two"), - Contains("one"), + Contains("active three").DoesNotContain("✓"), + Contains("active two").DoesNotContain("✓"), + Contains("target two").DoesNotContain("✓"), + Contains("target one").DoesNotContain("✓"), + Contains("three").DoesNotContain("✓"), + Contains("two").DoesNotContain("✓"), + Contains("one").DoesNotContain("✓"), ) }, }) diff --git a/pkg/integration/tests/demo/rebase_onto.go b/pkg/integration/tests/demo/rebase_onto.go new file mode 100644 index 000000000..381a2f050 --- /dev/null +++ b/pkg/integration/tests/demo/rebase_onto.go @@ -0,0 +1,81 @@ +package demo + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var RebaseOnto = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Rebase with '--onto' flag. We start with a feature branch on the develop branch that we want to rebase onto the master branch", + ExtraCmdArgs: []string{}, + Skip: false, + IsDemo: true, + SetupConfig: func(config *config.AppConfig) { + config.UserConfig.Gui.NerdFontsVersion = "3" + }, + SetupRepo: func(shell *Shell) { + shell.CreateNCommitsWithRandomMessages(60) + shell.NewBranch("develop") + + shell.SetAuthor("Joe Blow", "joeblow@gmail.com") + + shell.RandomChangeCommit("Develop commit 1") + shell.RandomChangeCommit("Develop commit 2") + shell.RandomChangeCommit("Develop commit 3") + + shell.SetAuthor("Jesse Duffield", "jesseduffield@gmail.com") + + shell.NewBranch("feature/demo") + + shell.RandomChangeCommit("Feature commit 1") + shell.RandomChangeCommit("Feature commit 2") + shell.RandomChangeCommit("Feature commit 3") + + shell.CloneIntoRemote("origin") + + shell.SetBranchUpstream("feature/demo", "origin/feature/demo") + shell.SetBranchUpstream("develop", "origin/develop") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.SetCaptionPrefix("Rebase from marked base commit") + t.Wait(1000) + + // first we focus the commits view, then expand to show the branches against each commit + // Then we go back to normal value, mark the last develop branch commit as the marked commit + // Then go to the branches view and press 'r' on the master branch to rebase onto it + // then we force push our changes. + + t.Views().Commits(). + Focus(). + Press(keys.Universal.PrevScreenMode). + Wait(500). + NavigateToLine(Contains("Develop commit 3")). + Wait(500). + Press(keys.Commits.MarkCommitAsBaseForRebase). + Wait(1000). + Press(keys.Universal.NextScreenMode). + Wait(500) + + t.Views().Branches(). + Focus(). + Wait(500). + NavigateToLine(Contains("master")). + Wait(500). + Press(keys.Branches.RebaseBranch). + Tap(func() { + t.ExpectPopup().Menu(). + Title(Contains("Rebase 'feature/demo' from marked base onto 'master'")). + Select(Contains("Simple rebase")). + Confirm() + }). + Wait(1000). + Press(keys.Universal.Push). + Tap(func() { + t.ExpectPopup().Confirmation(). + Title(Contains("Force push")). + Content(AnyString()). + Wait(500). + Confirm() + }) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 8c9527bec..a63481be0 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -98,6 +98,7 @@ var tests = []*components.IntegrationTest{ demo.Filter, demo.InteractiveRebase, demo.NukeWorkingTree, + demo.RebaseOnto, demo.StageLines, demo.Undo, demo.WorktreeCreateFromBranches, From 8dd517870dc14b3ecbaec02d9846d8c46e1ca2bf Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Mon, 7 Aug 2023 10:53:42 +1000 Subject: [PATCH 3/3] Add commit graph demo --- pkg/integration/components/random.go | 23 +++++++ pkg/integration/components/shell.go | 79 ++++++++++++++++++++++ pkg/integration/tests/demo/commit_graph.go | 79 ++++++++++++++++++++++ pkg/integration/tests/test_list.go | 1 + 4 files changed, 182 insertions(+) create mode 100644 pkg/integration/tests/demo/commit_graph.go diff --git a/pkg/integration/components/random.go b/pkg/integration/components/random.go index 808089e23..33dcf3ce8 100644 --- a/pkg/integration/components/random.go +++ b/pkg/integration/components/random.go @@ -472,3 +472,26 @@ func Encrypt(key []byte, plaintext []byte) ([]byte, error) { } `, } + +var RandomBranchNames = []string{ + "hotfix/fix-bug", + "r-u-fkn-srs", + "iserlohn-build", + "hotfix/fezzan-corridor", + "terra-investigation", + "quash-rebellion", + "feature/attack-on-odin", + "feature/peace-time", + "feature/repair-brunhild", + "feature/iserlohn-backdoor", + "bugfix/resolve-crash", + "enhancement/improve-performance", + "experimental/new-feature", + "release/v1.0.0", + "release/v2.0.0", + "chore/update-dependencies", + "docs/add-readme", + "refactor/cleanup-code", + "style/update-css", + "test/add-unit-tests", +} diff --git a/pkg/integration/components/shell.go b/pkg/integration/components/shell.go index 4cf0990d6..33b82fc58 100644 --- a/pkg/integration/components/shell.go +++ b/pkg/integration/components/shell.go @@ -3,10 +3,14 @@ package components import ( "fmt" "io" + "math/rand" "os" "os/exec" "path/filepath" "runtime" + "time" + + "github.com/jesseduffield/lazygit/pkg/utils" ) // this is for running shell commands, mostly for the sake of setting up the repo @@ -124,6 +128,10 @@ func (self *Shell) NewBranch(name string) *Shell { return self.RunCommand([]string{"git", "checkout", "-b", name}) } +func (self *Shell) NewBranchFrom(name string, from string) *Shell { + return self.RunCommand([]string{"git", "checkout", "-b", name, from}) +} + func (self *Shell) Checkout(name string) *Shell { return self.RunCommand([]string{"git", "checkout", name}) } @@ -152,6 +160,10 @@ func (self *Shell) EmptyCommit(message string) *Shell { return self.RunCommand([]string{"git", "commit", "--allow-empty", "-m", message}) } +func (self *Shell) EmptyCommitDaysAgo(message string, daysAgo int) *Shell { + return self.RunCommand([]string{"git", "commit", "--allow-empty", "--date", fmt.Sprintf("%d days ago", daysAgo), "-m", message}) +} + func (self *Shell) Revert(ref string) *Shell { return self.RunCommand([]string{"git", "revert", ref}) } @@ -223,6 +235,73 @@ func (self *Shell) CreateNCommitsWithRandomMessages(n int) *Shell { return self } +// This creates a repo history of commits +// It uses a branching strategy where each feature branch is directly branched off +// of the master branch +// Only to be used in demos +func (self *Shell) CreateRepoHistory() *Shell { + authors := []string{"Yang Wen-li", "Siegfried Kircheis", "Paul Oberstein", "Oscar Reuenthal", "Fredrica Greenhill"} + + numAuthors := 5 + numBranches := 10 + numInitialCommits := 20 + maxCommitsPerBranch := 5 + // Each commit will happen on a separate day + repoStartDaysAgo := 100 + + totalCommits := 0 + + // Generate commits + for i := 0; i < numInitialCommits; i++ { + author := authors[i%numAuthors] + commitMessage := RandomCommitMessages[totalCommits%len(RandomCommitMessages)] + + self.SetAuthor(author, "") + self.EmptyCommitDaysAgo(commitMessage, repoStartDaysAgo-totalCommits) + totalCommits++ + } + + // Generate branches and merges + for i := 0; i < numBranches; i++ { + // We'll have one author creating all the commits in the branch + author := authors[i%numAuthors] + branchName := RandomBranchNames[i%len(RandomBranchNames)] + + // Choose a random commit within the last 20 commits on the master branch + lastMasterCommit := totalCommits - 1 + commitOffset := rand.Intn(utils.Min(lastMasterCommit, 5)) + 1 + + // Create the feature branch and checkout the chosen commit + self.NewBranchFrom(branchName, fmt.Sprintf("master~%d", commitOffset)) + + numCommitsInBranch := rand.Intn(maxCommitsPerBranch) + 1 + for j := 0; j < numCommitsInBranch; j++ { + commitMessage := RandomCommitMessages[totalCommits%len(RandomCommitMessages)] + + self.SetAuthor(author, "") + self.EmptyCommitDaysAgo(commitMessage, repoStartDaysAgo-totalCommits) + totalCommits++ + } + + self.Checkout("master") + + prevCommitterDate := os.Getenv("GIT_COMMITTER_DATE") + prevAuthorDate := os.Getenv("GIT_AUTHOR_DATE") + + commitDate := time.Now().Add(time.Duration(totalCommits-repoStartDaysAgo) * time.Hour * 24) + os.Setenv("GIT_COMMITTER_DATE", commitDate.Format(time.RFC3339)) + os.Setenv("GIT_AUTHOR_DATE", commitDate.Format(time.RFC3339)) + + // Merge branch into master + self.RunCommand([]string{"git", "merge", "--no-ff", branchName, "-m", fmt.Sprintf("Merge %s into master", branchName)}) + + os.Setenv("GIT_COMMITTER_DATE", prevCommitterDate) + os.Setenv("GIT_AUTHOR_DATE", prevAuthorDate) + } + + return self +} + // Creates a commit with a random file // Only to be used in demos func (self *Shell) RandomChangeCommit(message string) *Shell { diff --git a/pkg/integration/tests/demo/commit_graph.go b/pkg/integration/tests/demo/commit_graph.go new file mode 100644 index 000000000..5ccaecf43 --- /dev/null +++ b/pkg/integration/tests/demo/commit_graph.go @@ -0,0 +1,79 @@ +package demo + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var CommitGraph = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Show commit graph", + ExtraCmdArgs: []string{"log"}, + Skip: false, + IsDemo: true, + SetupConfig: func(config *config.AppConfig) { + config.UserConfig.Gui.NerdFontsVersion = "3" + config.UserConfig.Gui.AuthorColors = map[string]string{ + "Fredrica Greenhill": "#fb5aa3", + "Oscar Reuenthal": "#86c82f", + "Paul Oberstein": "#ffd500", + "Siegfried Kircheis": "#fe7e11", + "Yang Wen-li": "#8e3ccb", + } + }, + SetupRepo: func(shell *Shell) { + shell.CreateRepoHistory() + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.SetCaptionPrefix("View commit log") + t.Wait(1000) + + t.Views().Commits(). + IsFocused(). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100). + SelectNextItem(). + Wait(100) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index a63481be0..44ff22514 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -93,6 +93,7 @@ var tests = []*components.IntegrationTest{ demo.Bisect, demo.CherryPick, demo.CommitAndPush, + demo.CommitGraph, demo.CustomCommand, demo.CustomPatch, demo.Filter,