Skip to content

Commit 3c110fc

Browse files
committed
update branch list api with new mocks and revised UT suite
1 parent 3e7cb77 commit 3c110fc

11 files changed

+283
-61
lines changed

api/repo_status.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
9696
*remoteURL = *remotes[0]
9797
}
9898

99-
branchListObj := branch.NewBranchList(repo)
99+
branchListObj := branch.NewBranchList(middleware.NewRepository(repo))
100100
branchList, _ := branchListObj.ListBranches()
101101

102102
currentBranch := branchList.CurrentBranch

generate_all_mocks.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mockgen -source=git/middleware/reference.go -destination=mocks/mock_reference.go
77
mockgen -source=git/middleware/index.go -destination=mocks/mock_index.go -package=mocks
88
mockgen -source=git/middleware/branch.go -destination=mocks/mock_branch.go -package=mocks
99
mockgen -source=git/middleware/commit.go -destination=mocks/mock_commit.go -package=mocks
10+
mockgen -source=git/middleware/branch_iterator.go -destination=mocks/mock_branch_iterator.go -package=mocks
1011

1112
# Commit mocks
1213
mockgen -source=git/commit/git_list_all_commit_logs.go -destination=git/commit/mocks/mock_git_list_all_commit_logs.go -package=mocks

git/branch/git_branch_list.go

Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package branch
22

33
import (
4+
"errors"
45
"fmt"
56
git2go "github.com/libgit2/git2go/v31"
67
"github.com/neel1996/gitconvex/git/middleware"
78
"github.com/neel1996/gitconvex/global"
89
"github.com/neel1996/gitconvex/graph/model"
9-
"go/types"
1010
"strings"
1111
)
1212

@@ -15,26 +15,23 @@ type List interface {
1515
}
1616

1717
type listBranch struct {
18-
repo *git2go.Repository
18+
repo middleware.Repository
1919
}
2020

21-
var (
22-
localBranchList []string
23-
allBranchList []string
24-
)
21+
type branches struct {
22+
localBranchList []string
23+
remoteBranchList []string
24+
combinedBranches []string
25+
}
2526

26-
// ListBranches fetches all the branches from the target repository
27-
// The result will be returned as a struct with the current branch and all the available branches
2827
func (l listBranch) ListBranches() (model.ListOfBranches, error) {
29-
var currentBranch string
28+
var (
29+
currentBranch string
30+
localBranchList []string
31+
allBranchList []string
32+
)
3033
repo := l.repo
3134

32-
validationErr := NewBranchFieldsValidation(middleware.NewRepository(repo)).ValidateBranchFields()
33-
if validationErr != nil {
34-
logger.Log(validationErr.Error(), global.StatusError)
35-
return model.ListOfBranches{}, validationErr
36-
}
37-
3835
head, headErr := repo.Head()
3936
if headErr != nil {
4037
logger.Log(fmt.Sprintf("Repo head is invalid -> %s", headErr.Error()), global.StatusError)
@@ -52,62 +49,83 @@ func (l listBranch) ListBranches() (model.ListOfBranches, error) {
5249
return model.ListOfBranches{}, itrErr
5350
}
5451

55-
err := l.runBranchIterator(localBranchIterator, currentBranch)
52+
allBranches, err := l.getAllBranches(localBranchIterator, currentBranch)
5653
if err != nil {
5754
logger.Log(err.Error(), global.StatusError)
5855
return model.ListOfBranches{}, err
5956
}
6057

58+
allBranchList = append(allBranchList, allBranches.combinedBranches...)
59+
localBranchList = append(localBranchList, allBranches.localBranchList...)
60+
6161
return model.ListOfBranches{
6262
CurrentBranch: currentBranch,
6363
BranchList: localBranchList,
6464
AllBranchList: allBranchList,
6565
}, nil
6666
}
6767

68-
func (l listBranch) runBranchIterator(localBranchIterator *git2go.BranchIterator, currentBranch string) error {
69-
err := localBranchIterator.ForEach(func(branch *git2go.Branch, branchType git2go.BranchType) error {
68+
func (l listBranch) getAllBranches(localBranchIterator middleware.BranchIterator, currentBranch string) (branches, error) {
69+
var (
70+
localBranches []string
71+
remoteBranches []string
72+
)
73+
74+
err := localBranchIterator.ForEach(func(b *git2go.Branch, branchType git2go.BranchType) error {
75+
branch := middleware.NewBranch(b)
7076
branchName, nameErr := branch.Name()
7177
if nameErr != nil {
72-
return types.Error{Msg: "Unable to fetch branch name"}
78+
return nameErr
7379
}
7480

75-
if !branch.IsTag() && !branch.IsNote() && branchName != currentBranch {
76-
l.classifyRemoteAndLocalBranches(branch, branchName, currentBranch)
81+
if branch.IsTag() || branch.IsNote() || branchName == currentBranch {
82+
return nil
7783
}
84+
85+
if branch.IsRemote() {
86+
prefixedRemoteBranchName, err := l.getPrefixedRemoteBranch(branchName, currentBranch)
87+
if err == nil {
88+
remoteBranches = append(remoteBranches, prefixedRemoteBranchName)
89+
}
90+
} else {
91+
localBranches = append(localBranches, branchName)
92+
}
93+
7894
return nil
7995
})
8096

81-
return err
97+
return branches{
98+
localBranchList: localBranches,
99+
remoteBranchList: remoteBranches,
100+
combinedBranches: append(localBranches, remoteBranches...),
101+
}, err
82102
}
83103

84-
func (l listBranch) classifyRemoteAndLocalBranches(branch *git2go.Branch, branchName string, currentBranch string) {
85-
if branch.IsRemote() && strings.Contains(branchName, "/") {
86-
l.getRemoteBranchName(branchName, currentBranch)
87-
} else {
88-
allBranchList = append(allBranchList, branchName)
89-
localBranchList = append(localBranchList, branchName)
104+
func (l listBranch) getPrefixedRemoteBranch(branchName string, currentBranch string) (string, error) {
105+
shortBranchName := l.getShortBranchName(branchName)
106+
107+
if shortBranchName != "HEAD" && shortBranchName != currentBranch {
108+
remoteBranchName := "remotes/" + branchName
109+
return remoteBranchName, nil
90110
}
111+
return "", errors.New("invalid remote branch")
91112
}
92113

93-
func (l listBranch) getRemoteBranchName(branchName string, currentBranch string) {
94-
splitString := strings.Split(branchName, "/")
95-
splitBranch := splitString[len(splitString)-1]
114+
func (l listBranch) getShortBranchName(b string) string {
115+
str := strings.Split(b, "/")
116+
branchName := str[len(str)-1]
96117

97-
if splitBranch != "HEAD" && splitBranch != currentBranch {
98-
concatRemote := "remotes/" + strings.Join(splitString, "/")
99-
allBranchList = append(allBranchList, concatRemote)
100-
}
118+
return branchName
101119
}
102120

103-
func getCurrentBranchName(head *git2go.Reference) string {
121+
func getCurrentBranchName(head middleware.Reference) string {
104122
branch := head.Name()
105123
splitCurrentBranch := strings.Split(branch, "/")
106124
branch = splitCurrentBranch[len(splitCurrentBranch)-1]
107125
return branch
108126
}
109127

110-
func NewBranchList(repo *git2go.Repository) List {
128+
func NewBranchList(repo middleware.Repository) List {
111129
return listBranch{
112130
repo: repo,
113131
}

git/branch/git_branch_list_test.go

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,83 @@
11
package branch
22

33
import (
4+
"errors"
45
"fmt"
6+
"github.com/golang/mock/gomock"
57
git2go "github.com/libgit2/git2go/v31"
8+
"github.com/neel1996/gitconvex/git/middleware"
9+
"github.com/neel1996/gitconvex/mocks"
610
"github.com/stretchr/testify/suite"
711
"os"
8-
"path/filepath"
912
"testing"
1013
)
1114

1215
type BranchListTestSuite struct {
1316
suite.Suite
14-
repo *git2go.Repository
15-
noHeadRepo *git2go.Repository
16-
branchList List
17+
repo middleware.Repository
18+
mockController *gomock.Controller
19+
mockRepo *mocks.MockRepository
20+
mockReference *mocks.MockReference
21+
mockIterator *mocks.MockBranchIterator
22+
mockBranch *mocks.MockBranch
23+
branchList List
1724
}
1825

1926
func TestBranchListTestSuite(t *testing.T) {
20-
//suite.Run(t, new(BranchListTestSuite))
27+
suite.Run(t, new(BranchListTestSuite))
2128
}
2229

2330
func (suite *BranchListTestSuite) SetupTest() {
2431
r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
2532
if err != nil {
2633
fmt.Println(err)
2734
}
28-
noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
29-
noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
3035

31-
suite.repo = r
32-
suite.noHeadRepo = noHeadRepo
33-
suite.branchList = NewBranchList(suite.repo)
36+
suite.mockController = gomock.NewController(suite.T())
37+
suite.repo = middleware.NewRepository(r)
38+
suite.mockRepo = mocks.NewMockRepository(suite.mockController)
39+
suite.mockReference = mocks.NewMockReference(suite.mockController)
40+
suite.mockIterator = mocks.NewMockBranchIterator(suite.mockController)
41+
suite.mockBranch = mocks.NewMockBranch(suite.mockController)
42+
suite.branchList = NewBranchList(suite.mockRepo)
3443
}
3544

3645
func (suite *BranchListTestSuite) TestListBranches_WhenRepoHasBranches_ShouldReturnBranchList() {
46+
suite.branchList = NewBranchList(suite.repo)
47+
3748
branchList, err := suite.branchList.ListBranches()
3849

3950
suite.Nil(err)
40-
suite.Greater(len(branchList.BranchList), 2)
41-
suite.Greater(len(branchList.AllBranchList), 2)
51+
suite.Equal(2, len(branchList.BranchList))
52+
suite.Equal(3, len(branchList.AllBranchList))
4253
suite.Equal("master", branchList.CurrentBranch)
4354
}
4455

45-
func (suite *BranchListTestSuite) TestListBranches_WhenRepoIsNil_ShouldReturnError() {
46-
suite.branchList = NewBranchList(nil)
47-
branchList, err := suite.branchList.ListBranches()
56+
func (suite *BranchListTestSuite) TestListBranches_WhenRepoHeadIsInvalid_ShouldReturnError() {
57+
suite.mockRepo.EXPECT().Head().Return(nil, errors.New("HEAD_ERROR"))
58+
59+
_, err := suite.branchList.ListBranches()
4860

4961
suite.NotNil(err)
50-
suite.Empty(branchList)
5162
}
5263

53-
func (suite *BranchListTestSuite) TestListBranches_WhenRepoHasNoHead_ShouldReturnError() {
54-
suite.branchList = NewBranchList(suite.noHeadRepo)
55-
branchList, err := suite.branchList.ListBranches()
64+
func (suite *BranchListTestSuite) TestListBranches_WhenNewBranchIteratorFails_ShouldReturnError() {
65+
suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
66+
suite.mockReference.EXPECT().Name().Return("refs/head/master")
67+
suite.mockRepo.EXPECT().NewBranchIterator(git2go.BranchAll).Return(nil, errors.New("ITERATOR_ERR"))
68+
69+
_, err := suite.branchList.ListBranches()
70+
71+
suite.NotNil(err)
72+
}
73+
74+
func (suite *BranchListTestSuite) TestListBranches_WhenBranchIteratorReturnsError_ShouldReturnError() {
75+
suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
76+
suite.mockReference.EXPECT().Name().Return("refs/head/master")
77+
suite.mockRepo.EXPECT().NewBranchIterator(git2go.BranchAll).Return(suite.mockIterator, nil)
78+
suite.mockIterator.EXPECT().ForEach(gomock.Any()).Return(errors.New("iterator error"))
79+
80+
_, err := suite.branchList.ListBranches()
5681

5782
suite.NotNil(err)
58-
suite.Empty(branchList)
5983
}

git/middleware/branch.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,32 @@ type Branch interface {
77
Delete() error
88
Cmp(r Reference) int
99
Reference() Reference
10+
IsRemote() bool
11+
Name() (string, error)
12+
IsTag() bool
13+
IsNote() bool
1014
}
1115

1216
type branch struct {
1317
branch *git2go.Branch
1418
}
1519

20+
func (b branch) IsNote() bool {
21+
return b.branch.IsNote()
22+
}
23+
24+
func (b branch) IsTag() bool {
25+
return b.branch.IsTag()
26+
}
27+
28+
func (b branch) Name() (string, error) {
29+
return b.branch.Name()
30+
}
31+
32+
func (b branch) IsRemote() bool {
33+
return b.branch.IsRemote()
34+
}
35+
1636
func (b branch) Reference() Reference {
1737
return NewReference(b.branch.Reference)
1838
}

git/middleware/branch_iterator.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package middleware
2+
3+
import git "github.com/libgit2/git2go/v31"
4+
5+
type BranchIterator interface {
6+
ForEach(func(b *git.Branch, branchType git.BranchType) error) error
7+
}
8+
9+
type branchIterator struct {
10+
iterator *git.BranchIterator
11+
}
12+
13+
func (b branchIterator) ForEach(f func(b *git.Branch, branchType git.BranchType) error) error {
14+
return b.iterator.ForEach(f)
15+
}
16+
17+
func NewBranchIterator(iterator *git.BranchIterator) BranchIterator {
18+
return branchIterator{iterator: iterator}
19+
}

git/middleware/repository.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,20 @@ type Repository interface {
1818
CheckoutTree(tree *git.Tree, c *git.CheckoutOptions) error
1919
SetHead(name string) error
2020
GetGitRepository() *git.Repository
21-
NewBranchIterator(branchType git.BranchType) (*git.BranchIterator, error)
21+
NewBranchIterator(branchType git.BranchType) (BranchIterator, error)
2222
}
2323

2424
type repository struct {
2525
repo *git.Repository
2626
}
2727

28-
func (r repository) NewBranchIterator(branchType git.BranchType) (*git.BranchIterator, error) {
29-
return r.repo.NewBranchIterator(branchType)
28+
func (r repository) NewBranchIterator(branchType git.BranchType) (BranchIterator, error) {
29+
itr, err := r.repo.NewBranchIterator(branchType)
30+
if err != nil {
31+
return nil, err
32+
}
33+
34+
return NewBranchIterator(itr), nil
3035
}
3136

3237
func (r repository) SetHead(name string) error {

0 commit comments

Comments
 (0)