Skip to content

Commit

Permalink
refactor: reduce cyclomatic complexity of Repositories.Overlay
Browse files Browse the repository at this point in the history
Add tests for the now-simpler methods, bringing `repositories`
coverage up to 100%.
  • Loading branch information
nisimond authored and retr0h committed Mar 6, 2024
1 parent 7503568 commit d4ab9c1
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 36 deletions.
96 changes: 60 additions & 36 deletions internal/repositories/repositories.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,49 +81,19 @@ func (r *Repositories) Overlay() error {
targetDir := r.cloneCache[c.Git]

// Easy mode: create a full worktree, directly in DstDir
if c.DstDir != "" {
// delete dstDir since `git worktree add` will not replace existing directories
if info, err := r.appFs.Stat(c.DstDir); err == nil && info.Mode().IsDir() {
if err := r.appFs.RemoveAll(c.DstDir); err != nil {
return err
}
}
if err := r.repoManager.Worktree(c, targetDir, c.DstDir); err != nil {
return err
}
if err := r.overlayTree(c, targetDir); err != nil {
return err
}

// Hard mode: copy subtrees of the worktree from Repository.Src to
// Repository.DstDir (or Repository.DstFile)
if len(c.Sources) > 0 {
giltDir, err := r.getGiltDir()
if err != nil {
return err
}
err = r.execManager.RunInTempDir(giltDir, "tmp", func(tmpDir string) error {
tmpClone := r.appFs.Join(tmpDir, r.appFs.Base(targetDir))
if err := r.repoManager.Worktree(c, targetDir, tmpClone); err != nil {
return err
}
return r.repoManager.CopySources(c, tmpClone)
})
if err != nil {
return err
}
if err := r.overlaySubtrees(c, targetDir); err != nil {
return err
}

// run post commands
if len(c.Commands) > 0 {
for _, command := range c.Commands {
r.logger.Info(
"executing command",
slog.String("cmd", command.Cmd),
slog.String("args", strings.Join(command.Args, " ")),
)
if err := r.execManager.RunCmd(command.Cmd, command.Args); err != nil {
return err
}
}
if err := r.runCommands(c); err != nil {
return err
}
}

Expand Down Expand Up @@ -155,3 +125,57 @@ func (r *Repositories) populateCloneCache() error {
}
return nil
}

func (r *Repositories) overlayTree(c config.Repository, targetDir string) error {
if c.DstDir == "" {
return nil
}
// delete DstDir since `git worktree add` will not replace existing directories
if info, err := r.appFs.Stat(c.DstDir); err == nil && info.IsDir() {
if err := r.appFs.RemoveAll(c.DstDir); err != nil {
return err
}
}
if err := r.repoManager.Worktree(c, targetDir, c.DstDir); err != nil {
return err
}
return nil
}

func (r *Repositories) overlaySubtrees(c config.Repository, targetDir string) error {
if len(c.Sources) == 0 {
return nil
}
giltDir, err := r.getGiltDir()
if err != nil {
return err
}
err = r.execManager.RunInTempDir(giltDir, "tmp", func(tmpDir string) error {
tmpClone := r.appFs.Join(tmpDir, r.appFs.Base(targetDir))
if err := r.repoManager.Worktree(c, targetDir, tmpClone); err != nil {
return err
}
return r.repoManager.CopySources(c, tmpClone)
})
if err != nil {
return err
}
return nil
}

func (r *Repositories) runCommands(c config.Repository) error {
if len(c.Commands) == 0 {
return nil
}
for _, command := range c.Commands {
r.logger.Info(
"executing command",
slog.String("cmd", command.Cmd),
slog.String("args", strings.Join(command.Args, " ")),
)
if err := r.execManager.RunCmd(command.Cmd, command.Args); err != nil {
return err
}
}
return nil
}
34 changes: 34 additions & 0 deletions internal/repositories/repositories_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
package repositories

import (
"fmt"
"log/slog"
"os"
"os/user"
"testing"

"github.com/avfs/avfs"
Expand All @@ -34,6 +36,7 @@ import (

"github.com/retr0h/gilt/v2/internal/mocks/exec"
"github.com/retr0h/gilt/v2/internal/mocks/repository"
"github.com/retr0h/gilt/v2/internal/path"
"github.com/retr0h/gilt/v2/pkg/config"
)

Expand Down Expand Up @@ -98,6 +101,19 @@ func (suite *RepositoriesTestSuite) TestgetCacheDir() {
assert.True(suite.T(), exists)
}

func (suite *RepositoriesTestSuite) TestgetCacheDirLookupError() {
repos := suite.NewTestRepositories("~" + suite.giltDir)
originalCurrentUser := path.CurrentUser
path.CurrentUser = func() (*user.User, error) {
return nil, fmt.Errorf("failed to get current user")
}
defer func() { path.CurrentUser = originalCurrentUser }()

got, err := repos.getCacheDir()
assert.Error(suite.T(), err)
assert.Equal(suite.T(), "", got)
}

func (suite *RepositoriesTestSuite) TestgetCacheDirCannotCreateError() {
// Replace the test FS with a read-only copy
suite.appFs = rofs.New(suite.appFs)
Expand All @@ -121,6 +137,24 @@ func (suite *RepositoriesTestSuite) TestPopulateCloneCacheDedupesCloneCalls() {
assert.NoError(suite.T(), err)
}

func (suite *RepositoriesTestSuite) TestOverlaySubtreesGiltDirLookupError() {
repos := suite.NewTestRepositories("~" + suite.giltDir)
originalCurrentUser := path.CurrentUser
path.CurrentUser = func() (*user.User, error) {
return nil, fmt.Errorf("failed to get current user")
}
defer func() { path.CurrentUser = originalCurrentUser }()
repos.config.Repositories = []config.Repository{
{
Git: suite.gitURL,
Version: "v1",
Sources: []config.Source{{Src: "srcDir", DstDir: "dstDir"}},
},
}
err := repos.overlaySubtrees(repos.config.Repositories[0], suite.giltDir)
assert.Error(suite.T(), err)
}

// In order for `go test` to run this suite, we need to create
// a normal test function and pass our suite to suite.Run.
func TestRepositoriesTestSuite(t *testing.T) {
Expand Down

0 comments on commit d4ab9c1

Please sign in to comment.