mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-04-23 12:18:51 +02:00
Add more demos to the README (#2866)
This commit is contained in:
commit
39d24fdeb7
18
README.md
18
README.md
@ -7,9 +7,9 @@
|
||||
A simple terminal UI for git commands
|
||||
<br/>
|
||||
|
||||
[](https://github.com/jesseduffield/lazygit/releases) [](https://goreportcard.com/report/github.com/jesseduffield/lazygit) [](https://golangci.com) [](https://github.com/jesseduffield/lazygit/releases/latest) [](https://github.com/Homebrew/homebrew-core/blob/master/Formula/lazygit.rb)
|
||||
[](https://github.com/jesseduffield/lazygit/releases) [](https://goreportcard.com/report/github.com/jesseduffield/lazygit) [](https://golangci.com) [](https://github.com/jesseduffield/lazygit/releases/latest) [](https://github.com/Homebrew/homebrew-core/blob/master/Formula/lazygit.rb)
|
||||
|
||||

|
||||

|
||||
|
||||
</div>
|
||||
|
||||
@ -316,25 +316,29 @@ See the [docs](docs/Custom_Command_Keybindings.md)
|
||||
|
||||
### Git Bisect
|
||||
|
||||

|
||||

|
||||
|
||||
### Cherry-pick
|
||||
|
||||

|
||||

|
||||
|
||||
### Interactive Rebase
|
||||
|
||||

|
||||

|
||||
|
||||
### Nuking the working tree
|
||||
|
||||
For when you really want to just get rid of anything that shows up when you run `git status` (and yes that includes dirty submodules) [kidpix style](https://www.youtube.com/watch?v=Ur7_A4JusMU)
|
||||
|
||||

|
||||

|
||||
|
||||
### Amend old commit
|
||||
|
||||

|
||||

|
||||
|
||||
### Stage individual lines
|
||||
|
||||

|
||||
|
||||
## Contributing
|
||||
|
||||
|
@ -1,15 +1,44 @@
|
||||
#!/bin/sh
|
||||
|
||||
TEST=$1
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "$TEST" ]
|
||||
TYPE=$1
|
||||
TEST=$2
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [gif|mp4] <test path>"
|
||||
echo "e.g. using full path: $0 gif pkg/integration/tests/demo/nuke_working_tree.go"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ "$#" -ne 2 ]
|
||||
then
|
||||
echo "Usage: $0 <test>"
|
||||
usage
|
||||
fi
|
||||
|
||||
if [ "$TYPE" != "gif" ] && [ "$TYPE" != "mp4" ]
|
||||
then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$TEST" ]
|
||||
then
|
||||
usage
|
||||
fi
|
||||
|
||||
WORKTREE_PATH=$(git worktree list | grep assets | awk '{print $1}')
|
||||
|
||||
if [ -z "$WORKTREE_PATH" ]
|
||||
then
|
||||
echo "Could not find assets worktree. You'll need to create a worktree for the assets branch using the following command:"
|
||||
echo "git worktree add .worktrees/assets assets"
|
||||
echo "The assets branch has no shared history with the main branch: it exists to store assets which are too large to store in the main branch."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OUTPUT_DIR="$WORKTREE_PATH/demo"
|
||||
|
||||
if ! command -v terminalizer &> /dev/null
|
||||
then
|
||||
echo "terminalizer could not be found"
|
||||
@ -24,18 +53,29 @@ then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# get last part of the test path and set that as the output name
|
||||
# Get last part of the test path and set that as the output name
|
||||
# example test path: pkg/integration/tests/01_basic_test.go
|
||||
# For that we want: NAME=01_basic_test
|
||||
NAME=$(echo "$TEST" | sed -e 's/.*\///' | sed -e 's/\..*//')
|
||||
|
||||
# Add the demo to the tests list (if missing) so that it can be run
|
||||
go generate pkg/integration/tests/tests.go
|
||||
|
||||
mkdir -p demo/output
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
terminalizer -c demo/config.yml record --skip-sharing -d "go run cmd/integration_test/main.go cli --slow $TEST" "demo/output/$NAME"
|
||||
terminalizer render "demo/output/$NAME" -o "demo/output/$NAME.gif"
|
||||
COMPRESSED_PATH="demo/output/$NAME-compressed.gif"
|
||||
gifsicle --colors 256 --use-col=web -O3 < "demo/output/$NAME.gif" > "$COMPRESSED_PATH"
|
||||
# First we record the demo into a yaml representation
|
||||
terminalizer -c demo/config.yml record --skip-sharing -d "go run cmd/integration_test/main.go cli --slow $TEST" "$OUTPUT_DIR/$NAME"
|
||||
# Then we render it into a gif
|
||||
terminalizer render "$OUTPUT_DIR/$NAME" -o "$OUTPUT_DIR/$NAME.gif"
|
||||
|
||||
# Then we convert it to either an mp4 or gif based on the command line argument
|
||||
if [ "$TYPE" = "mp4" ]
|
||||
then
|
||||
COMPRESSED_PATH="$OUTPUT_DIR/$NAME.mp4"
|
||||
ffmpeg -y -i "$OUTPUT_DIR/$NAME.gif" -movflags faststart -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" "$COMPRESSED_PATH"
|
||||
else
|
||||
COMPRESSED_PATH="$OUTPUT_DIR/$NAME-compressed.gif"
|
||||
gifsicle --colors 256 --use-col=web -O3 < "$OUTPUT_DIR/$NAME.gif" > "$COMPRESSED_PATH"
|
||||
fi
|
||||
|
||||
echo "Demo recorded to $COMPRESSED_PATH"
|
||||
|
@ -12,6 +12,8 @@ Ideally we'd run this whole thing through docker but we haven't got that working
|
||||
npm i -g terminalizer
|
||||
# for gif compression
|
||||
npm i -g gifsicle
|
||||
# for mp4 conversion
|
||||
brew install ffmpeg
|
||||
|
||||
# font with icons
|
||||
wget https://github.com/ryanoasis/nerd-fonts/releases/download/v3.0.2/DejaVuSansMono.tar.xz && \
|
||||
@ -37,16 +39,44 @@ You can use the same flow as we use with integration tests when you're writing a
|
||||
|
||||
It's good to add captions explaining what task if being performed. Use the existing demos as a guide.
|
||||
|
||||
### Setting up the assets worktree
|
||||
|
||||
We store assets (which includes demo recordings) in the `assets` branch, which is a branch that shares no history with the main branch and exists purely for storing assets. Storing them separately means we don't clog up the code branches with large binaries.
|
||||
|
||||
The scripts and demo definitions live in the code branches but the output lives in the assets branch so to be able to create a video from a demo you'll need to create a linked worktree for the assets branch which you can do with:
|
||||
|
||||
```sh
|
||||
git worktree add .worktrees/assets assets
|
||||
```
|
||||
|
||||
Outputs will be stored in `.worktrees/assets/demos/`. We'll store three separate things:
|
||||
* the yaml of the recording
|
||||
* the original gif
|
||||
* either the compressed gif or the mp4 depending on the output you chose (see below)
|
||||
|
||||
### Recording the demo
|
||||
|
||||
Once you're happy with your demo you can record it using:
|
||||
```sh
|
||||
scripts/record_demo.sh <path>
|
||||
scripts/record_demo.sh [gif|mp4] <path>
|
||||
# e.g.
|
||||
scripts/record_demo.sh pkg/integration/tests/demo/interactive_rebase.go
|
||||
scripts/record_demo.sh gif pkg/integration/tests/demo/interactive_rebase.go
|
||||
```
|
||||
|
||||
### Storing demos
|
||||
~~The gif format is for use in the first video of the readme (it has a larger size but has auto-play and looping)~~
|
||||
~~The mp4 format is for everything else (no looping, requires clicking, but smaller size).~~
|
||||
|
||||
This part is subject to change. I'm thinking of storing all gifs in the `assets` branch. But yet to finalize on that.
|
||||
For now, feel free to upload `demo/demo-compressed.gif` to GitHub by dragging and dropping it in a file in the browser (e.g. the README).
|
||||
Turns out that you can't store mp4s in a repo and link them from a README so we're gonna just use gifs across the board for now.
|
||||
|
||||
### Including demos in README/docs
|
||||
|
||||
If you've followed the above steps you'll end up with your output in your assets worktree.
|
||||
|
||||
Within that worktree, stage all three output files and raise a PR against the assets branch.
|
||||
|
||||
Then back in the code branch, in the doc, you can embed the recording like so:
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
This means we can update assets without needing to update the docs that embed them.
|
||||
|
@ -40,6 +40,12 @@ func (self *ConfirmationDriver) Cancel() {
|
||||
self.getViewDriver().PressEscape()
|
||||
}
|
||||
|
||||
func (self *ConfirmationDriver) Wait(milliseconds int) *ConfirmationDriver {
|
||||
self.getViewDriver().Wait(milliseconds)
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *ConfirmationDriver) checkNecessaryChecksCompleted() {
|
||||
if !self.hasCheckedContent || !self.hasCheckedTitle {
|
||||
self.t.Fail("You must both check the content and title of a confirmation popup by calling Title()/Content() before calling Confirm()/Cancel().")
|
||||
|
62
pkg/integration/tests/demo/amend_old_commit.go
Normal file
62
pkg/integration/tests/demo/amend_old_commit.go
Normal file
@ -0,0 +1,62 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var AmendOldCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Amend old commit",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
IsDemo: true,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
// No idea why I had to use version 2: it should be using my own computer's
|
||||
// font and the one iterm uses is version 3.
|
||||
config.UserConfig.Gui.NerdFontsVersion = "2"
|
||||
config.UserConfig.Gui.ShowFileTree = false
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.CreateNCommitsWithRandomMessages(60)
|
||||
shell.NewBranch("feature/demo")
|
||||
|
||||
shell.CloneIntoRemote("origin")
|
||||
|
||||
shell.SetBranchUpstream("feature/demo", "origin/feature/demo")
|
||||
|
||||
shell.UpdateFile("navigation/site_navigation.go", "package navigation\n\nfunc Navigate() {\n\tpanic(\"unimplemented\")\n}")
|
||||
shell.CreateFile("docs/README.md", "my readme content")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.SetCaptionPrefix("Amend an old commit")
|
||||
t.Wait(1000)
|
||||
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
SelectedLine(Contains("site_navigation.go")).
|
||||
PressPrimaryAction()
|
||||
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
NavigateToLine(Contains("Improve accessibility of site navigation")).
|
||||
Wait(500).
|
||||
Press(keys.Commits.AmendToCommit).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Confirmation().
|
||||
Title(Equals("Amend commit")).
|
||||
Wait(1000).
|
||||
Content(AnyString()).
|
||||
Confirm()
|
||||
|
||||
t.Wait(1000)
|
||||
}).
|
||||
Press(keys.Universal.Push).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Confirmation().
|
||||
Title(Equals("Force push")).
|
||||
Content(AnyString()).
|
||||
Wait(1000).
|
||||
Confirm()
|
||||
})
|
||||
},
|
||||
})
|
93
pkg/integration/tests/demo/filter.go
Normal file
93
pkg/integration/tests/demo/filter.go
Normal file
@ -0,0 +1,93 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var Filter = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Filter branches",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
IsDemo: true,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
// No idea why I had to use version 2: it should be using my own computer's
|
||||
// font and the one iterm uses is version 3.
|
||||
config.UserConfig.Gui.NerdFontsVersion = "2"
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.CreateNCommitsWithRandomMessages(30)
|
||||
shell.NewBranch("feature/user-authentication")
|
||||
shell.NewBranch("feature/payment-processing")
|
||||
shell.NewBranch("feature/search-functionality")
|
||||
shell.NewBranch("feature/mobile-responsive")
|
||||
shell.NewBranch("bugfix/fix-login-issue")
|
||||
shell.NewBranch("bugfix/fix-crash-bug")
|
||||
shell.NewBranch("bugfix/fix-validation-error")
|
||||
shell.NewBranch("refactor/improve-performance")
|
||||
shell.NewBranch("refactor/code-cleanup")
|
||||
shell.NewBranch("refactor/extract-method")
|
||||
shell.NewBranch("docs/update-readme")
|
||||
shell.NewBranch("docs/add-user-guide")
|
||||
shell.NewBranch("docs/api-documentation")
|
||||
shell.NewBranch("experiment/new-feature-idea")
|
||||
shell.NewBranch("experiment/try-new-library")
|
||||
shell.NewBranch("chore/update-dependencies")
|
||||
shell.NewBranch("chore/add-test-cases")
|
||||
shell.NewBranch("chore/migrate-database")
|
||||
shell.NewBranch("hotfix/critical-bug")
|
||||
shell.NewBranch("hotfix/security-patch")
|
||||
shell.NewBranch("feature/social-media-integration")
|
||||
shell.NewBranch("feature/email-notifications")
|
||||
shell.NewBranch("feature/admin-panel")
|
||||
shell.NewBranch("feature/analytics-dashboard")
|
||||
shell.NewBranch("bugfix/fix-registration-flow")
|
||||
shell.NewBranch("bugfix/fix-payment-bug")
|
||||
shell.NewBranch("refactor/improve-error-handling")
|
||||
shell.NewBranch("refactor/optimize-database-queries")
|
||||
shell.NewBranch("docs/improve-tutorials")
|
||||
shell.NewBranch("docs/add-faq-section")
|
||||
shell.NewBranch("experiment/try-alternative-algorithm")
|
||||
shell.NewBranch("experiment/implement-design-concept")
|
||||
shell.NewBranch("chore/update-documentation")
|
||||
shell.NewBranch("chore/improve-test-coverage")
|
||||
shell.NewBranch("chore/cleanup-codebase")
|
||||
shell.NewBranch("hotfix/critical-security-vulnerability")
|
||||
shell.NewBranch("hotfix/fix-production-issue")
|
||||
shell.NewBranch("feature/integrate-third-party-api")
|
||||
shell.NewBranch("feature/image-upload-functionality")
|
||||
shell.NewBranch("feature/localization-support")
|
||||
shell.NewBranch("feature/chat-feature")
|
||||
shell.NewBranch("bugfix/fix-broken-link")
|
||||
shell.NewBranch("bugfix/fix-css-styling")
|
||||
shell.NewBranch("refactor/improve-logging")
|
||||
shell.NewBranch("refactor/extract-reusable-component")
|
||||
shell.NewBranch("docs/add-changelog")
|
||||
shell.NewBranch("docs/update-api-reference")
|
||||
shell.NewBranch("experiment/implement-new-design")
|
||||
shell.NewBranch("experiment/try-different-architecture")
|
||||
shell.NewBranch("chore/clean-up-git-history")
|
||||
shell.NewBranch("chore/update-environment-configuration")
|
||||
shell.CreateFileAndAdd("env_config.rb", "EnvConfig.call(false)\n")
|
||||
shell.Commit("Update env config")
|
||||
shell.CreateFileAndAdd("env_config.rb", "# Turns out we need to pass true for this to work\nEnvConfig.call(true)\n")
|
||||
shell.Commit("Fix env config issue")
|
||||
shell.Checkout("docs/add-faq-section")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.SetCaptionPrefix("Fuzzy filter branches")
|
||||
t.Wait(1000)
|
||||
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
Wait(500).
|
||||
Press(keys.Universal.StartSearch).
|
||||
Tap(func() {
|
||||
t.Wait(500)
|
||||
|
||||
t.ExpectSearch().Type("environ").Confirm()
|
||||
}).
|
||||
Wait(500).
|
||||
PressEnter()
|
||||
},
|
||||
})
|
85
pkg/integration/tests/demo/stage_lines.go
Normal file
85
pkg/integration/tests/demo/stage_lines.go
Normal file
@ -0,0 +1,85 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var originalFile = `# Lazygit
|
||||
|
||||
Simple terminal UI for git commands
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
### Homebrew
|
||||
|
||||
`
|
||||
|
||||
var updatedFile = `# Lazygit
|
||||
|
||||
Simple terminal UI for git
|
||||
(Not too simple though)
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
### Homebrew
|
||||
|
||||
Just do brew install lazygit and bada bing bada
|
||||
boom you have begun on the path of laziness.
|
||||
|
||||
`
|
||||
|
||||
var StageLines = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Stage individual lines",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
IsDemo: true,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
// No idea why I had to use version 2: it should be using my own computer's
|
||||
// font and the one iterm uses is version 3.
|
||||
config.UserConfig.Gui.NerdFontsVersion = "2"
|
||||
config.UserConfig.Gui.ShowFileTree = false
|
||||
config.UserConfig.Gui.ShowCommandLog = false
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.NewBranch("docs-fix")
|
||||
shell.CreateNCommitsWithRandomMessages(30)
|
||||
shell.CreateFileAndAdd("docs/README.md", originalFile)
|
||||
shell.Commit("Update docs/README")
|
||||
shell.UpdateFile("docs/README.md", updatedFile)
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.SetCaptionPrefix("Stage individual lines")
|
||||
t.Wait(1000)
|
||||
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
PressEnter()
|
||||
|
||||
t.Views().Staging().
|
||||
IsFocused().
|
||||
Press(keys.Main.ToggleDragSelect).
|
||||
PressFast(keys.Universal.NextItem).
|
||||
PressFast(keys.Universal.NextItem).
|
||||
Wait(500).
|
||||
PressPrimaryAction().
|
||||
Wait(500).
|
||||
PressEscape()
|
||||
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Press(keys.Files.CommitChanges).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().CommitMessagePanel().
|
||||
Type("Update tagline").
|
||||
Confirm()
|
||||
})
|
||||
|
||||
t.Views().Commits().
|
||||
Focus()
|
||||
},
|
||||
})
|
@ -89,11 +89,14 @@ var tests = []*components.IntegrationTest{
|
||||
custom_commands.OmitFromHistory,
|
||||
custom_commands.SuggestionsCommand,
|
||||
custom_commands.SuggestionsPreset,
|
||||
demo.AmendOldCommit,
|
||||
demo.Bisect,
|
||||
demo.CherryPick,
|
||||
demo.CommitAndPush,
|
||||
demo.Filter,
|
||||
demo.InteractiveRebase,
|
||||
demo.NukeWorkingTree,
|
||||
demo.StageLines,
|
||||
diff.Diff,
|
||||
diff.DiffAndApplyPatch,
|
||||
diff.DiffCommits,
|
||||
|
Loading…
x
Reference in New Issue
Block a user