From 0551f29de99d1d9fe2640aaa71ce2adf76896f25 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Mon, 7 Aug 2023 21:28:21 +1000 Subject: Test bare repos with dotfile setup --- pkg/integration/components/paths.go | 7 -- pkg/integration/components/runner.go | 19 ++++-- pkg/integration/components/test.go | 38 ++++++----- pkg/integration/tests/test_list.go | 1 + .../tests/worktree/dotfile_bare_repo.go | 74 ++++++++++++++++++++++ 5 files changed, 112 insertions(+), 27 deletions(-) create mode 100644 pkg/integration/tests/worktree/dotfile_bare_repo.go diff --git a/pkg/integration/components/paths.go b/pkg/integration/components/paths.go index bacc96f81..d100e91fe 100644 --- a/pkg/integration/components/paths.go +++ b/pkg/integration/components/paths.go @@ -27,13 +27,6 @@ func (self Paths) ActualRepo() string { return filepath.Join(self.Actual(), "repo") } -// When an integration test first runs, we copy everything in the 'actual' directory, -// and copy it into the 'expected' directory so that future runs can be compared -// against what we expect. -func (self Paths) Expected() string { - return filepath.Join(self.root, "expected") -} - func (self Paths) Config() string { return filepath.Join(self.root, "used_config") } diff --git a/pkg/integration/components/runner.go b/pkg/integration/components/runner.go index 32acdf25f..908d7e1d8 100644 --- a/pkg/integration/components/runner.go +++ b/pkg/integration/components/runner.go @@ -6,9 +6,11 @@ import ( "os/exec" "path/filepath" - "github.com/jesseduffield/lazycore/pkg/utils" + lazycoreUtils "github.com/jesseduffield/lazycore/pkg/utils" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" ) const ( @@ -30,7 +32,7 @@ func RunTests( keyPressDelay int, maxAttempts int, ) error { - projectRootDir := utils.GetLazyRootDirectory() + projectRootDir := lazycoreUtils.GetLazyRootDirectory() err := os.Chdir(projectRootDir) if err != nil { return err @@ -177,8 +179,17 @@ func getLazygitCommand(test *IntegrationTest, paths Paths, rootDir string, sandb return nil, err } - cmdArgs := []string{tempLazygitPath(), "-debug", "--use-config-dir=" + paths.Config(), "--path=" + paths.ActualRepo()} - cmdArgs = append(cmdArgs, test.ExtraCmdArgs()...) + cmdArgs := []string{tempLazygitPath(), "-debug", "--use-config-dir=" + paths.Config()} + if !test.useCustomPath { + cmdArgs = append(cmdArgs, "--path="+paths.ActualRepo()) + } + resolvedExtraArgs := lo.Map(test.ExtraCmdArgs(), func(arg string, _ int) string { + return utils.ResolvePlaceholderString(arg, map[string]string{ + "actualPath": paths.Actual(), + "actualRepoPath": paths.ActualRepo(), + }) + }) + cmdArgs = append(cmdArgs, resolvedExtraArgs...) cmdObj := osCommand.Cmd.New(cmdArgs) diff --git a/pkg/integration/components/test.go b/pkg/integration/components/test.go index 130ce8774..af307beeb 100644 --- a/pkg/integration/components/test.go +++ b/pkg/integration/components/test.go @@ -35,10 +35,11 @@ type IntegrationTest struct { testDriver *TestDriver, keys config.KeybindingConfig, ) - gitVersion GitVersionRestriction - width int - height int - isDemo bool + gitVersion GitVersionRestriction + width int + height int + isDemo bool + useCustomPath bool } var _ integrationTypes.IntegrationTest = &IntegrationTest{} @@ -66,6 +67,10 @@ type NewIntegrationTestArgs struct { Height int // If true, this is not a test but a demo to be added to our docs IsDemo bool + // If true, the test won't invoke lazygit with the --path arg. + // Useful for when we're passing --git-dir and --work-tree (because --path is + // incompatible with those args) + UseCustomPath bool } type GitVersionRestriction struct { @@ -125,18 +130,19 @@ func NewIntegrationTest(args NewIntegrationTestArgs) *IntegrationTest { } return &IntegrationTest{ - name: name, - description: args.Description, - extraCmdArgs: args.ExtraCmdArgs, - extraEnvVars: args.ExtraEnvVars, - skip: args.Skip, - setupRepo: args.SetupRepo, - setupConfig: args.SetupConfig, - run: args.Run, - gitVersion: args.GitVersion, - width: args.Width, - height: args.Height, - isDemo: args.IsDemo, + name: name, + description: args.Description, + extraCmdArgs: args.ExtraCmdArgs, + extraEnvVars: args.ExtraEnvVars, + skip: args.Skip, + setupRepo: args.SetupRepo, + setupConfig: args.SetupConfig, + run: args.Run, + gitVersion: args.GitVersion, + width: args.Width, + height: args.Height, + isDemo: args.IsDemo, + useCustomPath: args.UseCustomPath, } } diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index f71a3981e..e3ef9bebc 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -245,6 +245,7 @@ var tests = []*components.IntegrationTest{ worktree.Crud, worktree.CustomCommand, worktree.DetachWorktreeFromBranch, + worktree.DotfileBareRepo, worktree.FastForwardWorktreeBranch, worktree.ForceRemoveWorktree, worktree.RemoveWorktreeFromBranch, diff --git a/pkg/integration/tests/worktree/dotfile_bare_repo.go b/pkg/integration/tests/worktree/dotfile_bare_repo.go new file mode 100644 index 000000000..f14ef9839 --- /dev/null +++ b/pkg/integration/tests/worktree/dotfile_bare_repo.go @@ -0,0 +1,74 @@ +package worktree + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +// Can't think of a better name than 'dotfile' repo: I'm using that +// because that's the case we're typically dealing with. + +var DotfileBareRepo = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Open lazygit in the worktree of a dotfile bare repo and add a file and commit", + ExtraCmdArgs: []string{"--git-dir={{.actualPath}}/.bare", "--work-tree={{.actualPath}}/repo"}, + Skip: true, + // passing this because we're explicitly passing --git-dir and --work-tree args + UseCustomPath: true, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + // we're going to have a directory structure like this: + // project + // - .bare + // - repo (the worktree) + // + // The first repo is called 'repo' because that's the + // directory that all lazygit tests start in + + // Delete the .git dir that all tests start with by default + shell.DeleteFile(".git") + + // Create a bare repo in the parent directory + shell.RunCommand([]string{"git", "init", "--bare", "../.bare"}) + shell.RunCommand([]string{"git", "--git-dir=../.bare", "--work-tree=.", "checkout", "-b", "mybranch"}) + shell.CreateFile("blah", "original content\n") + + // Add a file and commit + shell.RunCommand([]string{"git", "--git-dir=../.bare", "--work-tree=.", "add", "blah"}) + shell.RunCommand([]string{"git", "--git-dir=../.bare", "--work-tree=.", "commit", "-m", "initial commit"}) + + shell.UpdateFile("blah", "updated content\n") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Branches(). + Lines( + Contains("mybranch"), + ) + + t.Views().Commits(). + Lines( + Contains("initial commit"), + ) + + t.Views().Files(). + IsFocused(). + Lines( + Contains(" M blah"), // shows as modified + ). + PressPrimaryAction(). + Press(keys.Files.CommitChanges) + + t.ExpectPopup().CommitMessagePanel(). + Title(Equals("Commit summary")). + Type("Add blah"). + Confirm() + + t.Views().Files(). + IsEmpty() + + t.Views().Commits(). + Lines( + Contains("Add blah"), + Contains("initial commit"), + ) + }, +}) -- cgit v1.2.3 From 595e28d335c9874eb56f7de61a85586567cd8f8c Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Mon, 7 Aug 2023 22:08:12 +1000 Subject: Support bare worktrees where worktree does not have its own .git file This was on oversight on my part: I assumed that the --work-tree arg was always intended for use with linked worktrees which have a .git file pointing back to the repo. I'm honestly confused now: seems like there are three kinds of worktrees: * the main worktree of a non-bare repo * a linked worktree (with its own gitdir in the repo's worktrees/ dir) * a random folder which you specify as a worktree with the --work-tree arg I'm pretty sure the --work-tree arg is only intended to be used with this third kind or workree --- pkg/app/entry_point.go | 24 +++++++++------------- pkg/commands/git_commands/repo_paths.go | 22 ++++++++++++++++---- pkg/commands/git_commands/worktree_loader.go | 2 +- pkg/env/env.go | 11 +++++++++- pkg/gui/controllers/helpers/repos_helper.go | 2 +- .../tests/worktree/dotfile_bare_repo.go | 2 +- 6 files changed, 41 insertions(+), 22 deletions(-) diff --git a/pkg/app/entry_point.go b/pkg/app/entry_point.go index fc2a4c7c4..d1b573a71 100644 --- a/pkg/app/entry_point.go +++ b/pkg/app/entry_point.go @@ -63,8 +63,17 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes log.Fatal(absRepoPath + " is not a valid git repository.") } - cliArgs.WorkTree = absRepoPath cliArgs.GitDir = filepath.Join(absRepoPath, ".git") + err = os.Chdir(absRepoPath) + if err != nil { + log.Fatalf("Failed to change directory to %s: %v", absRepoPath, err) + } + } else if cliArgs.WorkTree != "" { + env.SetWorkTreeEnv(cliArgs.WorkTree) + + if err := os.Chdir(cliArgs.WorkTree); err != nil { + log.Fatalf("Failed to change directory to %s: %v", cliArgs.WorkTree, err) + } } if cliArgs.CustomConfigFile != "" { @@ -75,13 +84,6 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes os.Setenv("CONFIG_DIR", cliArgs.UseConfigDir) } - if cliArgs.WorkTree != "" { - err := os.Chdir(cliArgs.WorkTree) - if err != nil { - log.Fatalf("Failed to change directory to %s: %v", cliArgs.WorkTree, err) - } - } - if cliArgs.GitDir != "" { env.SetGitDirEnv(cliArgs.GitDir) } @@ -118,12 +120,6 @@ func Start(buildInfo *BuildInfo, integrationTest integrationTypes.IntegrationTes os.Exit(0) } - if cliArgs.WorkTree != "" { - if err := os.Chdir(cliArgs.WorkTree); err != nil { - log.Fatal(err.Error()) - } - } - tempDir, err := os.MkdirTemp("", "lazygit-*") if err != nil { log.Fatal(err.Error()) diff --git a/pkg/commands/git_commands/repo_paths.go b/pkg/commands/git_commands/repo_paths.go index 46fcb5d10..6921c21b6 100644 --- a/pkg/commands/git_commands/repo_paths.go +++ b/pkg/commands/git_commands/repo_paths.go @@ -91,10 +91,24 @@ func getRepoPathsAux( if err != nil { return nil, errors.Errorf("failed to get repo git dir path: %v", err) } - worktreeGitDirPath, err := worktreeGitDirPath(fs, currentPath) - if err != nil { - return nil, errors.Errorf("failed to get worktree git dir path: %v", err) + + var worktreeGitDirPath string + if env.GetWorkTreeEnv() != "" { + // This env is set when you pass --work-tree to lazygit. In that case, + // we're not dealing with a linked work-tree, we're dealing with a 'specified' + // worktree (for lack of a better term). In this case, the worktree has no + // .git file and it just contains a bunch of files: it has no idea it's + // pointed to by a bare repo. As such it does not have its own git dir within + // the bare repo's git dir. Instead, we just use the bare repo's git dir. + worktreeGitDirPath = repoGitDirPath + } else { + var err error + worktreeGitDirPath, err = getWorktreeGitDirPath(fs, currentPath) + if err != nil { + return nil, errors.Errorf("failed to get worktree git dir path: %v", err) + } } + repoName := path.Base(repoPath) return &RepoPaths{ @@ -110,7 +124,7 @@ func getRepoPathsAux( // Returns the path of the git-dir for the worktree. For linked worktrees, the worktree has // a .git file that points to the git-dir (which itself lives in the git-dir // of the repo) -func worktreeGitDirPath(fs afero.Fs, worktreePath string) (string, error) { +func getWorktreeGitDirPath(fs afero.Fs, worktreePath string) (string, error) { // if .git is a file, we're in a linked worktree, otherwise we're in // the main worktree dotGitPath := path.Join(worktreePath, ".git") diff --git a/pkg/commands/git_commands/worktree_loader.go b/pkg/commands/git_commands/worktree_loader.go index 687e9680a..0d5f01e34 100644 --- a/pkg/commands/git_commands/worktree_loader.go +++ b/pkg/commands/git_commands/worktree_loader.go @@ -58,7 +58,7 @@ func (self *WorktreeLoader) GetWorktrees() ([]*models.Worktree, error) { isPathMissing := self.pathExists(path) var gitDir string - gitDir, err := worktreeGitDirPath(self.Fs, path) + gitDir, err := getWorktreeGitDirPath(self.Fs, path) if err != nil { self.Log.Warnf("Could not find git dir for worktree %s: %v", path, err) } diff --git a/pkg/env/env.go b/pkg/env/env.go index c96bd18bd..1ade5b8c6 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -14,6 +14,15 @@ func SetGitDirEnv(value string) { os.Setenv("GIT_DIR", value) } -func UnsetGitDirEnv() { +func GetWorkTreeEnv() string { + return os.Getenv("GIT_WORK_TREE") +} + +func SetWorkTreeEnv(value string) { + os.Setenv("GIT_WORK_TREE", value) +} + +func UnsetGitLocationEnvVars() { _ = os.Unsetenv("GIT_DIR") + _ = os.Unsetenv("GIT_WORK_TREE") } diff --git a/pkg/gui/controllers/helpers/repos_helper.go b/pkg/gui/controllers/helpers/repos_helper.go index d4bd46f40..3ebd7767d 100644 --- a/pkg/gui/controllers/helpers/repos_helper.go +++ b/pkg/gui/controllers/helpers/repos_helper.go @@ -145,7 +145,7 @@ func (self *ReposHelper) DispatchSwitchToRepo(path string, contextKey types.Cont func (self *ReposHelper) DispatchSwitchTo(path string, errMsg string, contextKey types.ContextKey) error { return self.c.WithWaitingStatus(self.c.Tr.Switching, func(gocui.Task) error { - env.UnsetGitDirEnv() + env.UnsetGitLocationEnvVars() originalPath, err := os.Getwd() if err != nil { return nil diff --git a/pkg/integration/tests/worktree/dotfile_bare_repo.go b/pkg/integration/tests/worktree/dotfile_bare_repo.go index f14ef9839..86b2a0fb4 100644 --- a/pkg/integration/tests/worktree/dotfile_bare_repo.go +++ b/pkg/integration/tests/worktree/dotfile_bare_repo.go @@ -11,7 +11,7 @@ import ( var DotfileBareRepo = NewIntegrationTest(NewIntegrationTestArgs{ Description: "Open lazygit in the worktree of a dotfile bare repo and add a file and commit", ExtraCmdArgs: []string{"--git-dir={{.actualPath}}/.bare", "--work-tree={{.actualPath}}/repo"}, - Skip: true, + Skip: false, // passing this because we're explicitly passing --git-dir and --work-tree args UseCustomPath: true, SetupConfig: func(config *config.AppConfig) {}, -- cgit v1.2.3