Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support git repository checkouts using git worktree #5

Merged
merged 1 commit into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ import (
"time"

"github.com/choffmeister/git-describe-semver/internal"
"github.com/go-git/go-git/v5"
)

func run(dir string, opts internal.GenerateVersionOptions) (*string, error) {
repo, err := git.PlainOpen(dir)
repo, err := internal.OpenRepository(dir)
if err != nil {
return nil, fmt.Errorf("unable to open git repository: %v", err)
}
Expand Down
65 changes: 65 additions & 0 deletions internal/git.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
package internal

import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
)

const (
// Prefix found in .git files that point to another location
GitDirPrefix = "gitdir: "

GitDirName = ".git"
CommonDirName = "commondir"
)

// GitTagMap ...
func GitTagMap(repo git.Repository) (*map[string]string, error) {
iter, err := repo.Tags()
Expand Down Expand Up @@ -99,3 +111,56 @@ func GitDescribe(repo git.Repository) (*string, *int, *string, error) {
tagName := (*tags)[tagHash]
return &tagName, &counter, &headHash, nil
}

func OpenRepository(dir string) (*git.Repository, error) {
gitDir, err := FindGitDir(dir)
if err != nil {
return nil, err
}
enableCommonDir, err := shouldEnableCommondDir(gitDir)
if err != nil {
return nil, err
}
openOpts := &git.PlainOpenOptions{EnableDotGitCommonDir: enableCommonDir}
return git.PlainOpenWithOptions(dir, openOpts)
}

func shouldEnableCommondDir(gitDir string) (bool, error) {
cdPath := filepath.Join(gitDir, CommonDirName)
st, err := os.Stat(cdPath)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return false, nil
}
return false, err
}
if st.IsDir() {
return false, fmt.Errorf("expected to be a file, not directory: %s", cdPath)
}
return true, nil
}

func FindGitDir(dir string) (string, error) {
gitDirPath := filepath.Join(dir, GitDirName)
st, err := os.Stat(gitDirPath)
if err != nil {
return "", err
}
if st.IsDir() {
return gitDirPath, nil
}
// It is a file, read the contents
contents, err := os.ReadFile(gitDirPath)
if err != nil {
return "", err
}

line := string(contents)
if !strings.HasPrefix(line, GitDirPrefix) {
return "", fmt.Errorf(".git file has no %s prefix", GitDirPrefix)
}

gitdir := strings.Split(line[len(GitDirPrefix):], "\n")[0]
gitdir = strings.TrimSpace(gitdir)
return gitdir, nil
}
80 changes: 80 additions & 0 deletions internal/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package internal

import (
"io/ioutil"
"os"
"path/filepath"
"testing"

"github.com/go-git/go-git/v5"
Expand Down Expand Up @@ -112,3 +114,81 @@ func TestGitDescribeWithBranch(t *testing.T) {
repo.CreateTag("v2.0.0", commit3, nil)
test("v2.0.0", 1, commit4.String())
}

func setUpDotGitDirTest(assert *assert.Assertions) (string, string) {
testDir, err := os.MkdirTemp("", "test")
assert.NoError(err, "failed to create temp dir")

gitDirPath := filepath.Join(testDir, GitDirName)
err = os.Mkdir(gitDirPath, 0750)
assert.NoError(err, "failed to create git dir")

return testDir, gitDirPath
}

func setUpDotGitFileTest(assert *assert.Assertions) (string, string, string) {
testDir, err := os.MkdirTemp("", "test")
assert.NoError(err, "failed to create temp dir")

actualDotGitPath := filepath.Join(testDir, "actual")
err = os.Mkdir(actualDotGitPath, 0750)
assert.NoError(err, "failed to create actual git dir")

wtPath := filepath.Join(testDir, "my_worktree")
err = os.Mkdir(wtPath, 0750)
assert.NoError(err, "failed to create worktree dir")

wtDotGitPath := filepath.Join(wtPath, GitDirName)
contents := GitDirPrefix + actualDotGitPath
err = os.WriteFile(wtDotGitPath, []byte(contents), 0666)
assert.NoError(err, "failed to write git dir file in worktree")

return testDir, actualDotGitPath, wtPath
}

func TestFindGitDir(t *testing.T) {
t.Run(".git is a directory", func(t *testing.T) {
assert := assert.New(t)
testDir, gitDirPath := setUpDotGitDirTest(assert)
defer os.RemoveAll(testDir)

result, err := FindGitDir(testDir)
assert.NoError(err, "failed to find git dir")
assert.Equal(gitDirPath, result)
})
t.Run(".git is a file pointing to another directory", func(t *testing.T) {
assert := assert.New(t)
testDir, actualDotGitPath, wtPath := setUpDotGitFileTest(assert)
defer os.RemoveAll(testDir)

result, err := FindGitDir(wtPath)
assert.NoError(err, "failed to find git dir in worktree")
assert.Equal(actualDotGitPath, result)
})
}

func TestShouldEnableCommonDir(t *testing.T) {
t.Run(".git is a directory", func(t *testing.T) {
assert := assert.New(t)
testDir, gitDirPath := setUpDotGitDirTest(assert)
defer os.RemoveAll(testDir)

result, err := shouldEnableCommondDir(gitDirPath)
assert.NoError(err, "failed evaluating whether to enable commond dir")
assert.False(result)
})
t.Run(".git is a file pointing to another directory", func(t *testing.T) {
assert := assert.New(t)
testDir, actualDotGitPath, _ := setUpDotGitFileTest(assert)
defer os.RemoveAll(testDir)

cdPath := filepath.Join(actualDotGitPath, CommonDirName)
contents := "../my_worktree"
err := os.WriteFile(cdPath, []byte(contents), 0666)
assert.NoError(err, "failed writing commondir file")

result, err := shouldEnableCommondDir(actualDotGitPath)
assert.NoError(err, "failed evaluating whether to enable commond dir")
assert.True(result)
})
}