Skip to content

Commit

Permalink
Fix git detection for worktree on bare repo
Browse files Browse the repository at this point in the history
  • Loading branch information
gandarez committed Jan 7, 2024
1 parent 21e6310 commit 25150b0
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 32 deletions.
9 changes: 1 addition & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,6 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
Expand Down Expand Up @@ -433,16 +431,13 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand All @@ -452,8 +447,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down
8 changes: 7 additions & 1 deletion pkg/project/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,14 @@ func (f File) Detect() (Result, bool, error) {
return result, true, nil
}

// fileExists checks if a file or directory exist.
// fileExists checks if a file exist.
func fileExists(fp string) bool {
_, err := os.Stat(fp)
return err == nil
}

// fileOrDirExists checks if a file or directory exist.
func fileOrDirExists(fp string) bool {
_, err := os.Stat(fp)
return err == nil || os.IsExist(err)
}
Expand Down
35 changes: 21 additions & 14 deletions pkg/project/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (g Git) Detect() (Result, bool, error) {
fp := g.Filepath

// Take only the directory
if fileExists(fp) {
if fileOrDirExists(fp) {
fp = filepath.Dir(fp)
}

Expand Down Expand Up @@ -73,7 +73,9 @@ func (g Git) Detect() (Result, bool, error) {
return Result{}, false, fmt.Errorf("error finding gitdir: %s", err)
}

// Commonly .git file is present when it's a worktree
// Commonly .git folder is present when it's a worktree but there's an exception where
// worktree is present but .git folder is not present. In that case, we need to find
// for worktree folder.
// Find for commondir file
commondir, ok, err := findCommondir(gitdir)
if err != nil {
Expand All @@ -82,7 +84,16 @@ func (g Git) Detect() (Result, bool, error) {

// we found a commondir file so this is a worktree
if ok {
project := projectOrRemote(filepath.Base(filepath.Dir(commondir)), g.ProjectFromGitRemote, commondir)
dir := filepath.Dir(commondir)

// Commonly commondir file contains a .git folder but there's an exception where
// commondir contains the actual git folder. It's common when repo is bare and
// it's a worktree.
if strings.LastIndex(commondir, ".git") == -1 {
dir = commondir
}

project := projectOrRemote(filepath.Base(dir), g.ProjectFromGitRemote, commondir)

branch, err := findGitBranch(filepath.Join(gitdir, "HEAD"))
if err != nil {
Expand All @@ -96,7 +107,7 @@ func (g Git) Detect() (Result, bool, error) {
return Result{
Project: project,
Branch: branch,
Folder: filepath.Dir(commondir),
Folder: dir,
}, true, nil
}

Expand Down Expand Up @@ -198,13 +209,13 @@ func findGitdir(fp string) (string, error) {
return "", nil
}

func resolveGitdir(fp string, gitdir string) (string, error) {
func resolveGitdir(fp, gitdir string) (string, error) {
subPath := strings.TrimSpace(gitdir)
if !filepath.IsAbs(subPath) {
subPath = filepath.Join(fp, subPath)
}

if fileExists(filepath.Join(subPath, "HEAD")) {
if fileOrDirExists(filepath.Join(subPath, "HEAD")) {
return subPath, nil
}

Expand All @@ -220,7 +231,7 @@ func findCommondir(fp string) (string, bool, error) {
return "", false, nil
}

if fileExists(filepath.Join(fp, "commondir")) {
if fileOrDirExists(filepath.Join(fp, "commondir")) {
return resolveCommondir(fp)
}

Expand All @@ -244,11 +255,7 @@ func resolveCommondir(fp string) (string, bool, error) {
fmt.Errorf("failed to get absolute path: %s", err)
}

if filepath.Base(gitdir) == ".git" {
return gitdir, true, nil
}

return "", false, nil
return gitdir, true, nil
}

func projectOrRemote(projectName string, projectFromGitRemote bool, dotGitFolder string) string {
Expand All @@ -273,7 +280,7 @@ func projectOrRemote(projectName string, projectFromGitRemote bool, dotGitFolder
}

func findGitBranch(fp string) (string, error) {
if !fileExists(fp) {
if !fileOrDirExists(fp) {
return "master", nil
}

Expand All @@ -290,7 +297,7 @@ func findGitBranch(fp string) (string, error) {
}

func findGitRemote(fp string) (string, error) {
if !fileExists(fp) {
if !fileOrDirExists(fp) {
return "", nil
}

Expand Down
81 changes: 81 additions & 0 deletions pkg/project/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,45 @@ func TestGit_Detect_WorktreeGitRemote(t *testing.T) {
}, result)
}

func TestGit_Detect_Worktree_BareRepo(t *testing.T) {
fp := setupTestGitWorktreeBareRepo(t)

g := project.Git{
Filepath: filepath.Join(fp, "wakatime-cli/master/src/pkg/file.go"),
}

result, detected, err := g.Detect()
require.NoError(t, err)

assert.True(t, detected)
assert.Contains(t, result.Folder, filepath.Join(fp, "wakatime-cli"))
assert.Equal(t, project.Result{
Project: "wakatime-cli",
Branch: "feature/api",
Folder: result.Folder,
}, result)
}

func TestGit_Detect_WorktreeGitRemote_BareRepo(t *testing.T) {
fp := setupTestGitWorktreeBareRepo(t)

g := project.Git{
Filepath: filepath.Join(fp, "wakatime-cli/master/src/pkg/file.go"),
ProjectFromGitRemote: true,
}

result, detected, err := g.Detect()
require.NoError(t, err)

assert.True(t, detected)
assert.Contains(t, result.Folder, filepath.Join(fp, "wakatime-cli"))
assert.Equal(t, project.Result{
Project: "wakatime/wakatime-cli",
Branch: "feature/api",
Folder: result.Folder,
}, result)
}

func TestGit_Detect_Submodule(t *testing.T) {
fp := setupTestGitSubmodule(t)

Expand Down Expand Up @@ -456,6 +495,48 @@ func setupTestGitWorktree(t *testing.T) (fp string) {
return tmpDir
}

func setupTestGitWorktreeBareRepo(t *testing.T) (fp string) {
tmpDir := t.TempDir()

tmpDir, err := realpath.Realpath(tmpDir)
require.NoError(t, err)

if runtime.GOOS == "windows" {
tmpDir = windows.FormatFilePath(tmpDir)
}

// Create directories
err = os.MkdirAll(filepath.Join(tmpDir, "wakatime-cli/worktrees/master"), os.FileMode(int(0700)))
require.NoError(t, err)

err = os.MkdirAll(filepath.Join(tmpDir, "wakatime-cli/master/src/pkg"), os.FileMode(int(0700)))
require.NoError(t, err)

// Create fake file
tmpFile, err := os.Create(filepath.Join(tmpDir, "wakatime-cli/master/src/pkg/file.go"))
require.NoError(t, err)

defer tmpFile.Close()

// Setup basic git
copyFile(t, "testdata/git_basic/config", filepath.Join(tmpDir, "wakatime-cli/config"))
copyFile(t, "testdata/git_worktree/HEAD", filepath.Join(tmpDir, "wakatime-cli/HEAD"))

// Setup git worktree
copyFile(t, "testdata/git_worktree/HEAD2", filepath.Join(tmpDir, "wakatime-cli/worktrees/master/HEAD"))
copyFile(t, "testdata/git_worktree/commondir", filepath.Join(tmpDir, "wakatime-cli/worktrees/master/commondir"))

tmpFile, err = os.Create(filepath.Join(tmpDir, "wakatime-cli/master/.git"))
require.NoError(t, err)

defer tmpFile.Close()

_, err = tmpFile.WriteString(fmt.Sprintf("gitdir: %s/wakatime-cli/worktrees/master", tmpDir))
require.NoError(t, err)

return tmpDir
}

func setupTestGitSubmodule(t *testing.T) (fp string) {
tmpDir := t.TempDir()

Expand Down
4 changes: 2 additions & 2 deletions pkg/project/mercurial.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func (m Mercurial) Detect() (Result, bool, error) {
var fp string

// Take only the directory
if fileExists(m.Filepath) {
if fileOrDirExists(m.Filepath) {
fp = filepath.Dir(m.Filepath)
}

Expand Down Expand Up @@ -49,7 +49,7 @@ func (m Mercurial) Detect() (Result, bool, error) {

func findHgBranch(fp string) (string, error) {
p := filepath.Join(fp, "branch")
if !fileExists(p) {
if !fileOrDirExists(p) {
return "default", nil
}

Expand Down
31 changes: 27 additions & 4 deletions pkg/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,29 @@ func CountSlashesInProjectFolder(directory string) int {
return strings.Count(directory, `/`)
}

// FindFile searches for a file named `filename`.
// Search starts in `directory` and will traverse through all parent directories.
func FindFile(directory, filename string) (string, bool) {
i := 0
for i < maxRecursiveIteration {
if isRootPath(directory) {
return "", false
}

if fileExists(filepath.Join(directory, filename)) {
return filepath.Join(directory, filename), true
}

directory = filepath.Clean(filepath.Join(directory, ".."))

i++
}

log.Warnf("max %d iterations reached without finding %s", maxRecursiveIteration, filename)

return "", false
}

// FindFileOrDirectory searches for a file or directory named `filename`.
// Search starts in `directory` and will traverse through all parent directories.
// `directory` may also be a file, and in that case will start from the file's directory.
Expand All @@ -630,7 +653,7 @@ func FindFileOrDirectory(directory, filename string) (string, bool) {
return "", false
}

if fileExists(filepath.Join(directory, filename)) {
if fileOrDirExists(filepath.Join(directory, filename)) {
return filepath.Join(directory, filename), true
}

Expand All @@ -648,10 +671,10 @@ func isRootPath(directory string) bool {
return (directory == "" ||
directory == "." ||
directory == string(filepath.Separator) ||
directory == "\\\\wsl$" ||
driveLetterRegex.MatchString(directory) ||
directory == filepath.Dir(directory)) ||
directory == filepath.VolumeName(directory) ||
directory == filepath.Dir(directory))
directory == "\\\\wsl$" ||
driveLetterRegex.MatchString(directory)
}

// firstNonEmptyString accepts multiple values and return the first non empty string value.
Expand Down
2 changes: 1 addition & 1 deletion pkg/project/subversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (s Subversion) Detect() (Result, bool, error) {
var fp string

// Take only the directory
if fileExists(s.Filepath) {
if fileOrDirExists(s.Filepath) {
fp = filepath.Dir(s.Filepath)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/project/tfvc.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func (t Tfvc) Detect() (Result, bool, error) {
var fp string

// Take only the directory
if fileExists(t.Filepath) {
if fileOrDirExists(t.Filepath) {
fp = filepath.Dir(t.Filepath)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/remote/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func WithCleanup() heartbeat.HandleOption {

for _, h := range hh {
if h.LocalFileNeedsCleanup {
log.Debugln("deleting temporary file: %s", h.LocalFile)
log.Debugln("deleting temporary file:", h.LocalFile)

deleteLocalFile(h.LocalFile)
}
Expand Down

0 comments on commit 25150b0

Please sign in to comment.