diff --git a/README.md b/README.md index ed60a75..c18faa1 100644 --- a/README.md +++ b/README.md @@ -279,6 +279,7 @@ All flags have a matching option function to configure the previous commands bey - `svu.Next(svu.WithTagMode(svu.AllBranches))` or `svu.Next(svu.ForAllBranches())` - `svu.Next(svu.WithTagMode(svu.CurrentBranch))` or `svu.Next(svu.ForCurrentBranch())` - `svu.Next(svu.ForcePatchIncrement())` +- `svu.Current(svu.WithGitDirectory("/some/other/repo/.git"), svu.WithGitWorkTree("/some/other/repo"))` Or multiple options: diff --git a/internal/git/git.go b/internal/git/git.go index 471119d..db6812e 100644 --- a/internal/git/git.go +++ b/internal/git/git.go @@ -3,7 +3,9 @@ package git import ( "errors" "fmt" + "os" "os/exec" + "path/filepath" "strings" "github.com/gobwas/glob" @@ -16,26 +18,64 @@ const ( // copied from goreleaser -// IsRepo returns true if current folder is a git repository -func IsRepo() bool { - out, err := run("rev-parse", "--is-inside-work-tree") - return err == nil && strings.TrimSpace(out) == "true" +type Repository struct { + GitWorkTree string + GitDirectory string } -func getAllTags(args ...string) ([]string, error) { - tags, err := run(append([]string{"-c", "versionsort.suffix=-", "tag", "--sort=-version:refname"}, args...)...) +// NewRepository creates a Repository. gitworktree and gitdirectory will default to 'pwd' and 'pwd/.git' +func NewRepository(gitworktree, gitdirectory string) (*Repository, error) { + var err error + if gitworktree == "" { + gitworktree, err = os.Getwd() + if err != nil { + return nil, err + } + } + gitworktree = filepath.Clean(gitworktree) + if gitdirectory == "" { + gitdirectory, err = os.Getwd() + if err != nil { + return nil, err + } + gitdirectory = filepath.Join(gitdirectory, ".git") + } + gitdirectory = filepath.Clean(gitdirectory) + + r := &Repository{ + GitWorkTree: gitworktree, + GitDirectory: gitdirectory, + } + return r, nil +} + +// IsRepo returns true if the current work-tree and git-dir are considered a git repository by the git binary. +// unless specified by --work-tree and --git-dir, the current working directory will be considered +func (r *Repository) IsRepo() bool { + _, err := r.run("status") + return err == nil +} + +// Root returns the root of the git Repository +func (r *Repository) Root() (string, error) { + out, err := r.run("rev-parse", "--show-toplevel") + return strings.TrimSpace(out), err +} + +func (r *Repository) getAllTags(args ...string) ([]string, error) { + tags, err := r.run(append([]string{"-c", "versionsort.suffix=-", "tag", "--sort=-version:refname"}, args...)...) if err != nil { return nil, err } return strings.Split(tags, "\n"), nil } -func DescribeTag(tagMode string, pattern string) (string, error) { +func (r *Repository) DescribeTag(tagMode string, pattern string) (string, error) { args := []string{} if tagMode == CurrentBranchTagMode { args = []string{"--merged"} } - tags, err := getAllTags(args...) + tags, err := r.getAllTags(args...) if err != nil { return "", err } @@ -59,17 +99,21 @@ func DescribeTag(tagMode string, pattern string) (string, error) { return "", fmt.Errorf("no tags match '%s'", pattern) } -func Changelog(tag string, dir string) (string, error) { +func (r *Repository) Changelog(tag string, dir string) (string, error) { if tag == "" { - return gitLog(dir, "HEAD") + return r.gitLog(dir, "HEAD") } else { - return gitLog(dir, fmt.Sprintf("tags/%s..HEAD", tag)) + return r.gitLog(dir, fmt.Sprintf("tags/%s..HEAD", tag)) } } -func run(args ...string) (string, error) { - extraArgs := []string{ - "-c", "log.showSignature=false", +func (r *Repository) run(args ...string) (string, error) { + extraArgs := []string{"-c", "log.showSignature=false"} + if r.GitWorkTree != "" { + extraArgs = append(extraArgs, fmt.Sprintf("--work-tree=%s", r.GitWorkTree)) + } + if r.GitDirectory != "" { + extraArgs = append(extraArgs, fmt.Sprintf("--git-dir=%s", r.GitDirectory)) } args = append(extraArgs, args...) /* #nosec */ @@ -81,11 +125,11 @@ func run(args ...string) (string, error) { return string(bts), nil } -func gitLog(dir string, refs ...string) (string, error) { +func (r *Repository) gitLog(dir string, refs ...string) (string, error) { args := []string{"log", "--no-decorate", "--no-color"} args = append(args, refs...) if dir != "" { args = append(args, "--", dir) } - return run(args...) + return r.run(args...) } diff --git a/internal/git/git_test.go b/internal/git/git_test.go index e7be156..e9d84ef 100644 --- a/internal/git/git_test.go +++ b/internal/git/git_test.go @@ -3,6 +3,7 @@ package git import ( "os" "path" + "path/filepath" "strings" "testing" "time" @@ -10,25 +11,66 @@ import ( "github.com/matryer/is" ) -func TestIsRepo(t *testing.T) { +func TestNewRepository(t *testing.T) { + cwd := currentWorkingDirectory(t) + cgd := filepath.Join(cwd, ".git") + + t.Run("defaults", func(t *testing.T) { + is := is.New(t) + r, err := NewRepository("", "") + is.NoErr(err) + is.Equal(r.GitWorkTree, cwd) + is.Equal(r.GitDirectory, cgd) + }) + + t.Run("only gitworktree set", func(t *testing.T) { + gwt := "/idk/some/git/work/tree/location" + is := is.New(t) + r, err := NewRepository(gwt, "") + is.NoErr(err) + is.Equal(r.GitWorkTree, gwt) + is.Equal(r.GitDirectory, cgd) + }) + + t.Run("only gitdir set", func(t *testing.T) { + gd := "/idk/some/git/location" + is := is.New(t) + r, err := NewRepository("", gd) + is.NoErr(err) + is.Equal(r.GitWorkTree, cwd) + is.Equal(r.GitDirectory, gd) + }) + + t.Run("gitworktree and gitdir set", func(t *testing.T) { + is := is.New(t) + r, err := NewRepository(cwd, cgd) + is.NoErr(err) + is.Equal(r.GitWorkTree, cwd) + is.Equal(r.GitDirectory, cgd) + }) +} + +func TestRepository_IsRepo(t *testing.T) { t.Run("is not a repo", func(t *testing.T) { - tempdir(t) + tempdir(t, true) + r := Repository{} is := is.New(t) - is.Equal(false, IsRepo()) // should not be arepo + is.Equal(false, r.IsRepo()) // should not be arepo }) t.Run("is a repo", func(t *testing.T) { - tempdir(t) + tempdir(t, true) gitInit(t) + r := Repository{} is := is.New(t) - is.True(IsRepo()) // should be arepo + is.True(r.IsRepo()) // should be arepo }) } -func TestDescribeTag(t *testing.T) { +func TestRepository_DescribeTag(t *testing.T) { setup := func(tb testing.TB) { tb.Helper() - tempdir(tb) + tempdir(tb, true) gitInit(tb) gitCommit(tb, "chore: foobar") gitTag(tb, "pattern-1.2.3") @@ -49,7 +91,8 @@ func TestDescribeTag(t *testing.T) { t.Run("normal", func(t *testing.T) { setup(t) is := is.New(t) - tag, err := DescribeTag("current-branch", "") + r := Repository{} + tag, err := r.DescribeTag("current-branch", "") is.NoErr(err) is.Equal("v1.2.4", tag) }) @@ -57,7 +100,8 @@ func TestDescribeTag(t *testing.T) { t.Run("all-branches", func(t *testing.T) { setup(t) is := is.New(t) - tag, err := DescribeTag("all-branches", "") + r := Repository{} + tag, err := r.DescribeTag("all-branches", "") is.NoErr(err) is.Equal("v1.2.5", tag) }) @@ -65,14 +109,15 @@ func TestDescribeTag(t *testing.T) { t.Run("pattern", func(t *testing.T) { setup(t) is := is.New(t) - tag, err := DescribeTag("current-branch", "pattern-*") + r := Repository{} + tag, err := r.DescribeTag("current-branch", "pattern-*") is.NoErr(err) is.Equal("pattern-1.2.3", tag) }) } -func TestChangelog(t *testing.T) { - tempdir(t) +func TestRepository_Changelog(t *testing.T) { + tempdir(t, true) gitInit(t) gitCommit(t, "chore: foobar") gitCommit(t, "lalalala") @@ -85,7 +130,8 @@ func TestChangelog(t *testing.T) { gitCommit(t, msg) } is := is.New(t) - log, err := Changelog("v1.2.3", "") + r := Repository{} + log, err := r.Changelog("v1.2.3", "") is.NoErr(err) for _, msg := range []string{ "chore: foobar", @@ -96,10 +142,11 @@ func TestChangelog(t *testing.T) { } } -func TestChangelogWithDirectory(t *testing.T) { - tempDir := tempdir(t) - localDir := dir(tempDir, t) - file := tempfile(t, localDir) +func TestRepository_ChangelogWithDirectory(t *testing.T) { + tempDir := tempdir(t, true) + localDir := dir(tempDir, "a-folder", t) + defer func() { os.RemoveAll(localDir) }() + file := tempfile(t, localDir, "a-file.txt") gitInit(t) gitCommit(t, "chore: foobar") gitCommit(t, "lalalala") @@ -108,13 +155,105 @@ func TestChangelogWithDirectory(t *testing.T) { gitAdd(t, file) gitCommit(t, "chore: filtered dir") is := is.New(t) - log, err := Changelog("v1.2.3", localDir) + r := Repository{} + log, err := r.Changelog("v1.2.3", localDir) is.NoErr(err) is.True(strings.Contains(log, "chore: filtered dir")) is.True(!strings.Contains(log, "feat: foobar")) } +func TestRepository_run(t *testing.T) { + // current directory: . , ./.git + rootGWT := currentWorkingDirectory(t) + rootGD := filepath.Join(rootGWT, ".git") + + t.Run("current directory", func(t *testing.T) { + is := is.New(t) + rootRepository := Repository{ + GitWorkTree: rootGWT, + GitDirectory: rootGD, + } + _, err := rootRepository.run("init") + is.NoErr(err) + is.True(rootRepository.IsRepo()) + actualRootGWT, err := rootRepository.run("rev-parse", "--show-toplevel") + is.NoErr(err) + actualRootGWT = strings.TrimSuffix(actualRootGWT, "\n") // git adds a new line to the cli output + is.Equal(actualRootGWT, rootGWT) + actualGitDir, err := rootRepository.run("rev-parse", "--absolute-git-dir") + is.NoErr(err) + actualGitDir = strings.TrimSuffix(actualGitDir, "\n") // git adds a new line to the cli output + is.Equal(actualGitDir, rootGD) + }) + + // subdirectory: ./foo , ./foo/.git + subGWT := dir(currentWorkingDirectory(t), "foo", t) + subGD := dir(subGWT, ".git", t) + + t.Run("subdirectory", func(t *testing.T) { + is := is.New(t) + subfolderRepository := Repository{ + GitWorkTree: subGWT, + GitDirectory: subGD, + } + _, err := subfolderRepository.run("init") + is.NoErr(err) + is.True(subfolderRepository.IsRepo()) + actualGWT, err := subfolderRepository.run("rev-parse", "--show-toplevel") + is.NoErr(err) + actualGWT = strings.TrimSuffix(actualGWT, "\n") // git adds a new line to the cli output + is.Equal(actualGWT, subGWT) + actualGitDir, err := subfolderRepository.run("rev-parse", "--absolute-git-dir") + is.NoErr(err) + actualGitDir = strings.TrimSuffix(actualGitDir, "\n") // git adds a new line to the cli output + is.Equal(actualGitDir, subGD) + }) + + // external: /temp/sdfjklds , /temp/sdfjklds/.git + externalGWT := tempdir(t, false) + externalGD := dir(externalGWT, ".git", t) + tmpGWTFileName := "somefile.txt" + tmpGWTFilePath := tempfile(t, externalGWT, tmpGWTFileName) + expectedGWTContent, _ := dataFromFile(tmpGWTFilePath) + tmpGDFileName := "somefile.txt" + tmpGDFilePath := tempfile(t, externalGD, tmpGDFileName) + expectedGDContent, _ := dataFromFile(tmpGDFilePath) + + t.Run("external directory", func(t *testing.T) { + is := is.New(t) + externalRepository := Repository{ + GitWorkTree: externalGWT, + GitDirectory: externalGD, + } + _, err := externalRepository.run("init") + is.NoErr(err) + is.True(externalRepository.IsRepo()) + actualGWT, err := externalRepository.run("rev-parse", "--show-toplevel") + is.NoErr(err) + actualGWT = strings.TrimSuffix(actualGWT, "\n") // git adds a new line to the cli output + // compare file content instead of having to deal with symlink paths + actualWTContent, err := dataFromFile(actualGWT + string(os.PathSeparator) + tmpGWTFileName) + is.NoErr(err) + is.Equal(expectedGWTContent, actualWTContent) + + actualGD, err := externalRepository.run("rev-parse", "--absolute-git-dir") + is.NoErr(err) + actualGD = strings.TrimSuffix(actualGD, "\n") // git adds a new line to the cli output + actualGDContent, err := dataFromFile(actualGD + string(os.PathSeparator) + tmpGDFileName) + is.NoErr(err) + is.Equal(expectedGDContent, actualGDContent) + }) +} + +func dataFromFile(filePath string) ([]byte, error) { + file, err := os.ReadFile(filePath) + if err != nil { + return nil, err + } + return file, nil +} + func switchToBranch(tb testing.TB, branch string) { is := is.New(tb) _, err := fakeGitRun("switch", branch) @@ -151,31 +290,36 @@ func gitInit(tb testing.TB) { is.NoErr(err) } -func tempdir(tb testing.TB) string { +// tempdir create a temporary directory and optionally cd into it +func tempdir(tb testing.TB, cdToTempDir bool) string { is := is.New(tb) previous, err := os.Getwd() is.NoErr(err) - tb.Cleanup(func() { - is.NoErr(os.Chdir(previous)) - }) dir := tb.TempDir() - is.NoErr(os.Chdir(dir)) - tb.Logf("cd into %s", dir) + tb.TempDir() + if cdToTempDir { + tb.Cleanup(func() { + is.NoErr(os.Chdir(previous)) + }) + is.NoErr(os.Chdir(dir)) + tb.Logf("cd into %s", dir) + } return dir } -func dir(tempDir string, tb testing.TB) string { +func dir(tempDir, subfolder string, tb testing.TB) string { is := is.New(tb) - createdDir := path.Join(tempDir, "a-folder") + createdDir := path.Join(tempDir, subfolder) err := os.Mkdir(createdDir, 0755) + tb.Cleanup(func() { os.RemoveAll(createdDir) }) is.NoErr(err) return createdDir } -func tempfile(tb testing.TB, dir string) string { +func tempfile(tb testing.TB, dir, filename string) string { is := is.New(tb) d1 := []byte("hello\ngo\n") - file := path.Join(dir, "a-file.txt") + file := path.Join(dir, filename) err := os.WriteFile(file, d1, 0644) is.NoErr(err) return file @@ -190,5 +334,13 @@ func fakeGitRun(args ...string) (string, error) { "-c", "log.showSignature=false", } allArgs = append(allArgs, args...) - return run(allArgs...) + r := Repository{} + return r.run(allArgs...) +} + +func currentWorkingDirectory(tb *testing.T) string { + is := is.New(tb) + getwd, err := os.Getwd() + is.NoErr(err) + return getwd } diff --git a/internal/svu/svu.go b/internal/svu/svu.go index 90aac80..db4ba5b 100644 --- a/internal/svu/svu.go +++ b/internal/svu/svu.go @@ -37,10 +37,16 @@ type Options struct { TagMode string ForcePatchIncrement bool PreventMajorIncrementOnV0 bool + GitWorkTree string + GitDirectory string } func Version(opts Options) (string, error) { - tag, err := git.DescribeTag(string(opts.TagMode), opts.Pattern) + r, err := git.NewRepository(opts.GitWorkTree, opts.GitDirectory) + if err != nil { + return "", fmt.Errorf("failed finding the repository: %w", err) + } + tag, err := r.DescribeTag(string(opts.TagMode), opts.Pattern) if err != nil { return "", fmt.Errorf("failed to get current tag for repo: %w", err) } @@ -51,6 +57,7 @@ func Version(opts Options) (string, error) { } result, err := nextVersion( + r, string(opts.Cmd), current, tag, @@ -70,7 +77,7 @@ func Version(opts Options) (string, error) { return opts.Prefix + result.String(), nil } -func nextVersion(cmd string, current *semver.Version, tag, preRelease, build, directory string, preventMajorIncrementOnV0, forcePatchIncrement bool) (semver.Version, error) { +func nextVersion(r *git.Repository, cmd string, current *semver.Version, tag, preRelease, build, directory string, preventMajorIncrementOnV0, forcePatchIncrement bool) (semver.Version, error) { if cmd == CurrentCmd { return *current, nil } @@ -91,7 +98,7 @@ func nextVersion(cmd string, current *semver.Version, tag, preRelease, build, di var err error switch cmd { case NextCmd, PreReleaseCmd: - result, err = findNextWithGitLog(current, tag, directory, preventMajorIncrementOnV0, forcePatchIncrement) + result, err = findNextWithGitLog(r, current, tag, directory, preventMajorIncrementOnV0, forcePatchIncrement) case MajorCmd: result = current.IncMajor() case MinorCmd: @@ -181,8 +188,8 @@ func getCurrentVersion(tag, prefix string) (*semver.Version, error) { return current, err } -func findNextWithGitLog(current *semver.Version, tag string, directory string, preventMajorIncrementOnV0, forcePatchIncrement bool) (semver.Version, error) { - log, err := git.Changelog(tag, directory) +func findNextWithGitLog(r *git.Repository, current *semver.Version, tag string, directory string, preventMajorIncrementOnV0, forcePatchIncrement bool) (semver.Version, error) { + log, err := r.Changelog(tag, directory) if err != nil { return semver.Version{}, fmt.Errorf("failed to get changelog: %w", err) } diff --git a/internal/svu/svu_test.go b/internal/svu/svu_test.go index 341c69f..8417718 100644 --- a/internal/svu/svu_test.go +++ b/internal/svu/svu_test.go @@ -1,6 +1,7 @@ package svu import ( + "github.com/caarlos0/svu/v2/internal/git" "reflect" "testing" @@ -103,17 +104,18 @@ func TestFindNext(t *testing.T) { func TestCmd(t *testing.T) { ver := func() *semver.Version { return semver.MustParse("1.2.3-pre+123") } + r := &git.Repository{} t.Run(CurrentCmd, func(t *testing.T) { cmd := CurrentCmd t.Run("version has meta", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, ver(), "v1.2.3", "", "", "", false, false) + v, err := nextVersion(r, cmd, ver(), "v1.2.3", "", "", "", false, false) is.NoErr(err) is.Equal("1.2.3-pre+123", v.String()) }) t.Run("version is clean", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, semver.MustParse("v1.2.3"), "v1.2.3", "doesnt matter", "nope", "", false, true) + v, err := nextVersion(r, cmd, semver.MustParse("v1.2.3"), "v1.2.3", "doesnt matter", "nope", "", false, true) is.NoErr(err) is.Equal("1.2.3", v.String()) }) @@ -123,25 +125,25 @@ func TestCmd(t *testing.T) { cmd := MinorCmd t.Run("no meta", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, ver(), "v1.2.3", "", "", "", false, false) + v, err := nextVersion(r, cmd, ver(), "v1.2.3", "", "", "", false, false) is.NoErr(err) is.Equal("1.3.0", v.String()) }) t.Run("build", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, ver(), "v1.2.3", "", "124", "", false, false) + v, err := nextVersion(r, cmd, ver(), "v1.2.3", "", "124", "", false, false) is.NoErr(err) is.Equal("1.3.0+124", v.String()) }) t.Run("prerel", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, ver(), "v1.2.3", "alpha.1", "", "", false, false) + v, err := nextVersion(r, cmd, ver(), "v1.2.3", "alpha.1", "", "", false, false) is.NoErr(err) is.Equal("1.3.0-alpha.1", v.String()) }) t.Run("all meta", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, ver(), "v1.2.3", "alpha.2", "125", "", false, false) + v, err := nextVersion(r, cmd, ver(), "v1.2.3", "alpha.2", "125", "", false, false) is.NoErr(err) is.Equal("1.3.0-alpha.2+125", v.String()) }) @@ -151,49 +153,49 @@ func TestCmd(t *testing.T) { cmd := PatchCmd t.Run("no meta", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, semver.MustParse("1.2.3"), "v1.2.3", "", "", "", false, false) + v, err := nextVersion(r, cmd, semver.MustParse("1.2.3"), "v1.2.3", "", "", "", false, false) is.NoErr(err) is.Equal("1.2.4", v.String()) }) t.Run("previous had meta", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, semver.MustParse("1.2.3-alpha.1+1"), "v1.2.3", "", "", "", false, false) + v, err := nextVersion(r, cmd, semver.MustParse("1.2.3-alpha.1+1"), "v1.2.3", "", "", "", false, false) is.NoErr(err) is.Equal("1.2.3", v.String()) }) t.Run("previous had meta, force", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, semver.MustParse("1.2.3-alpha.1+1"), "v1.2.3", "", "", "", false, true) + v, err := nextVersion(r, cmd, semver.MustParse("1.2.3-alpha.1+1"), "v1.2.3", "", "", "", false, true) is.NoErr(err) is.Equal("1.2.4", v.String()) }) t.Run("previous had meta, force, add meta", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, semver.MustParse("1.2.3-alpha.1+1"), "v1.2.3-alpha.1+1", "alpha.2", "10", "", false, true) + v, err := nextVersion(r, cmd, semver.MustParse("1.2.3-alpha.1+1"), "v1.2.3-alpha.1+1", "alpha.2", "10", "", false, true) is.NoErr(err) is.Equal("1.2.4-alpha.2+10", v.String()) }) t.Run("previous had meta, change it", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, semver.MustParse("1.2.3-alpha.1+1"), "v1.2.3-alpha.1+1", "alpha.2", "10", "", false, false) + v, err := nextVersion(r, cmd, semver.MustParse("1.2.3-alpha.1+1"), "v1.2.3-alpha.1+1", "alpha.2", "10", "", false, false) is.NoErr(err) is.Equal("1.2.3-alpha.2+10", v.String()) }) t.Run("build", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, semver.MustParse("1.2.3"), "v1.2.3", "", "124", "", false, false) + v, err := nextVersion(r, cmd, semver.MustParse("1.2.3"), "v1.2.3", "", "124", "", false, false) is.NoErr(err) is.Equal("1.2.4+124", v.String()) }) t.Run("prerel", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, semver.MustParse("1.2.3"), "v1.2.3", "alpha.1", "", "", false, false) + v, err := nextVersion(r, cmd, semver.MustParse("1.2.3"), "v1.2.3", "alpha.1", "", "", false, false) is.NoErr(err) is.Equal("1.2.4-alpha.1", v.String()) }) t.Run("all meta", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, semver.MustParse("1.2.3"), "v1.2.3", "alpha.2", "125", "", false, false) + v, err := nextVersion(r, cmd, semver.MustParse("1.2.3"), "v1.2.3", "alpha.2", "125", "", false, false) is.NoErr(err) is.Equal("1.2.4-alpha.2+125", v.String()) }) @@ -203,25 +205,25 @@ func TestCmd(t *testing.T) { cmd := MajorCmd t.Run("no meta", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, ver(), "v1.2.3", "", "", "", false, false) + v, err := nextVersion(r, cmd, ver(), "v1.2.3", "", "", "", false, false) is.NoErr(err) is.Equal("2.0.0", v.String()) }) t.Run("build", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, ver(), "v1.2.3", "", "124", "", false, false) + v, err := nextVersion(r, cmd, ver(), "v1.2.3", "", "124", "", false, false) is.NoErr(err) is.Equal("2.0.0+124", v.String()) }) t.Run("prerel", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, ver(), "v1.2.3", "alpha.1", "", "", false, false) + v, err := nextVersion(r, cmd, ver(), "v1.2.3", "alpha.1", "", "", false, false) is.NoErr(err) is.Equal("2.0.0-alpha.1", v.String()) }) t.Run("all meta", func(t *testing.T) { is := is.New(t) - v, err := nextVersion(cmd, ver(), "v1.2.3", "alpha.2", "125", "", false, false) + v, err := nextVersion(r, cmd, ver(), "v1.2.3", "alpha.2", "125", "", false, false) is.NoErr(err) is.Equal("2.0.0-alpha.2+125", v.String()) }) @@ -230,12 +232,12 @@ func TestCmd(t *testing.T) { t.Run("errors", func(t *testing.T) { t.Run("invalid build", func(t *testing.T) { is := is.New(t) - _, err := nextVersion(MinorCmd, semver.MustParse("1.2.3"), "v1.2.3", "", "+125", "", false, false) + _, err := nextVersion(r, MinorCmd, semver.MustParse("1.2.3"), "v1.2.3", "", "+125", "", false, false) is.True(err != nil) }) t.Run("invalid prerelease", func(t *testing.T) { is := is.New(t) - _, err := nextVersion(MinorCmd, semver.MustParse("1.2.3"), "v1.2.3", "+aaa", "", "", false, false) + _, err := nextVersion(r, MinorCmd, semver.MustParse("1.2.3"), "v1.2.3", "+aaa", "", "", false, false) is.True(err != nil) }) }) diff --git a/main.go b/main.go index 378e969..3cd519f 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,7 @@ var ( currentCmd = app.Command("current", "prints current version").Alias("c") preReleaseCmd = app.Command("prerelease", "new pre release version based on the next version calculated from git log"). Alias("pr") - preRelease = app.Flag("pre-release", "adds a pre-release suffix to the version, without the semver mandatory dash prefix"). + preRelease = app.Flag("pre-release", "adds a pre-release suffix to the version, without the semver mandatory dash prefix"). String() pattern = app.Flag("pattern", "limits calculations to be based on tags matching the given pattern").String() prefix = app.Flag("prefix", "set a custom prefix").Default("v").String() @@ -29,6 +29,9 @@ var ( tagMode = app.Flag("tag-mode", "determines if latest tag of the current or all branches will be used"). Default("current-branch"). Enum("current-branch", "all-branches") + gitWorkTree = app.Flag("git-work-tree", "sets the git work-tree directory where the git repository exists"). + Default("").String() + gitDirectory = app.Flag("git-directory", "sets the directory where the .git folder exists").Default("").String() forcePatchIncrement = nextCmd.Flag("force-patch-increment", "forces a patch version increment regardless of the commit message content"). Default("false"). Bool() @@ -53,6 +56,8 @@ func main() { Build: *build, Directory: *directory, TagMode: *tagMode, + GitWorkTree: *gitWorkTree, + GitDirectory: *gitDirectory, ForcePatchIncrement: *forcePatchIncrement, PreventMajorIncrementOnV0: *preventMajorIncrementOnV0, }) diff --git a/pkg/svu/svu.go b/pkg/svu/svu.go index 0b9831e..3b40afe 100644 --- a/pkg/svu/svu.go +++ b/pkg/svu/svu.go @@ -102,6 +102,18 @@ func ForcePatchIncrement() option { return WithForcePatchIncrement(true) } +func WithGitWorkTree(directory string) option { + return func(o *svu.Options) { + o.GitWorkTree = directory + } +} + +func WithGitDirectory(directory string) option { + return func(o *svu.Options) { + o.GitDirectory = directory + } +} + func version(opts ...option) (string, error) { options := &svu.Options{ Cmd: svu.NextCmd,