From 1dbe603c657a87f1123c576c5fa0b00f4b89d441 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 13 Jun 2021 00:43:53 +0530
Subject: [PATCH 001/148] update the default dir setup logic to make it more
 homebrew friendly

---
 .gitignore                          |  2 ++
 generators/default_dir_const_gen.go | 28 ++++++++++++++++++++++++++++
 global/default_dir_const.go         |  5 +++++
 go.mod                              |  2 +-
 go.sum                              |  5 ++++-
 server.go                           |  2 ++
 utils/default_dir_setup.go          | 22 ++++++----------------
 7 files changed, 48 insertions(+), 18 deletions(-)
 create mode 100644 generators/default_dir_const_gen.go
 create mode 100644 global/default_dir_const.go

diff --git a/.gitignore b/.gitignore
index 76a17a9..4db4c48 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,5 @@ env_config.json
 gitclient
 /*.exe
 /*.dll
+gitconvex
+gitconvex-server
diff --git a/generators/default_dir_const_gen.go b/generators/default_dir_const_gen.go
new file mode 100644
index 0000000..4de1dff
--- /dev/null
+++ b/generators/default_dir_const_gen.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"text/template"
+)
+
+func main() {
+	templateString := fmt.Sprintf("package global\n\nfunc GetDefaultDirectory() string {\n\treturn \"{{ .DefaultDirFromEnv }}\"\n}\n")
+	var fileTemplate = template.Must(template.New("").Parse(templateString))
+
+	var defaultDirFromEnv = os.Getenv("GITCONVEX_DEFAULT_PATH")
+	file, fileErr := os.Create("./global/default_dir_const.go")
+	if fileErr != nil {
+		log.Fatal(fileErr.Error())
+	}
+
+	err := fileTemplate.ExecuteTemplate(file, "", struct {
+		DefaultDirFromEnv string
+	}{
+		DefaultDirFromEnv: defaultDirFromEnv,
+	})
+	if err != nil {
+		log.Fatal(err.Error())
+	}
+}
diff --git a/global/default_dir_const.go b/global/default_dir_const.go
new file mode 100644
index 0000000..90c6d37
--- /dev/null
+++ b/global/default_dir_const.go
@@ -0,0 +1,5 @@
+package global
+
+func GetDefaultDirectory() string {
+	return "GENERATED_ENV_STRING_GOES_HERE"
+}
diff --git a/go.mod b/go.mod
index da2f322..e693def 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
 	github.com/libgit2/git2go/v31 v31.4.10
 	github.com/rs/cors v1.7.0
 	github.com/sirupsen/logrus v1.8.1
-	github.com/stretchr/testify v1.4.0
+	github.com/stretchr/testify v1.7.0
 	github.com/vektah/gqlparser/v2 v2.1.0
 	golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c
 )
diff --git a/go.sum b/go.sum
index 23462a2..f0dd038 100644
--- a/go.sum
+++ b/go.sum
@@ -61,8 +61,9 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
 github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
 github.com/vektah/gqlparser/v2 v2.1.0 h1:uiKJ+T5HMGGQM2kRKQ8Pxw8+Zq9qhhZhz/lieYvCMns=
@@ -96,5 +97,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
 sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=
diff --git a/server.go b/server.go
index b19e0e4..d12f50a 100644
--- a/server.go
+++ b/server.go
@@ -24,6 +24,8 @@ var (
 
 var logger global.Logger
 
+//go:generate go run ./generators/default_dir_const_gen.go
+
 func main() {
 	versionFlag := flag.Bool("version", false, "To get the current version of gitconvex")
 	portFlag := flag.String("port", "", "To define the port dynamically while starting gitconvex")
diff --git a/utils/default_dir_setup.go b/utils/default_dir_setup.go
index 45a0747..bbba1d2 100644
--- a/utils/default_dir_setup.go
+++ b/utils/default_dir_setup.go
@@ -1,7 +1,6 @@
 package utils
 
 import (
-	"flag"
 	"github.com/neel1996/gitconvex/global"
 	"go/types"
 	"os"
@@ -10,19 +9,10 @@ import (
 )
 
 func DefaultDirSetup() (string, error) {
-	var baseDirPath *string
-	baseDirFlag := flag.Lookup("basedir")
+	baseDirPath := global.GetDefaultDirectory()
 
-	if baseDirFlag == nil {
-		baseDirPath = flag.String("basedir", "/usr/local/gitconvex", "Default gitconvex directory path for Linux and MacOS")
-		flag.Parse()
-	} else {
-		flagPath := baseDirFlag.Value.String()
-		baseDirPath = &flagPath
-	}
-
-	if baseDirPath == nil {
-		return "", types.Error{Msg: "Unable to parse basedir flag"}
+	if baseDirPath == "" {
+		return "", types.Error{Msg: "Default directory path value is empty"}
 	}
 
 	if runtime.GOOS == "windows" {
@@ -38,15 +28,15 @@ func DefaultDirSetup() (string, error) {
 		return execPath, nil
 	}
 
-	_, statErr := os.Stat(*baseDirPath)
+	_, statErr := os.Stat(baseDirPath)
 	if statErr != nil {
-		err := os.Mkdir(*baseDirPath, 0755)
+		err := os.Mkdir(baseDirPath, 0644)
 		if err != nil {
 			logger.Log(err.Error(), global.StatusError)
 			return "", err
 		}
 	} else {
-		return *baseDirPath, nil
+		return baseDirPath, nil
 	}
 
 	return "", nil

From 57b3372b68de23cbc13b5ed49f8d0e326fcdd547 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 13 Jun 2021 16:34:21 +0530
Subject: [PATCH 002/148] revise test repo handling to enable teardown and add
 env variables in actions yaml

---
 .github/workflows/go-collab.yml   |  2 ++
 .github/workflows/go.yml          |  2 ++
 .gitignore                        |  1 +
 tests/beforeAll_git_clone_test.go | 19 ++++++++++++++++++-
 utils/env_file_handler.go         |  1 +
 5 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index db366e6..f19e825 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -20,6 +20,7 @@ jobs:
     env:
       PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
       GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/starfleet
+      GITCONVEX_DEFAULT_PATH: /usr/local/gitconvex
 
     steps:
       - name: Install libgit2 from Homebrew
@@ -43,6 +44,7 @@ jobs:
           git config --global user.name "${{ secrets.ACTION_USER_NAME }}" && git config --global user.email "${{ secrets.ACTION_USER_EMAIL }}"
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
+          go generate
           go test -v ./...
 
   gitconvex-build:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index b74479a..ab365e3 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -20,6 +20,7 @@ jobs:
     env:
       PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
       GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/starfleet
+      GITCONVEX_DEFAULT_PATH: /usr/local/gitconvex
 
     steps:
       - name: Install libgit2 from Homebrew
@@ -43,6 +44,7 @@ jobs:
           git config --global user.name "${{ secrets.ACTION_USER_NAME }}" && git config --global user.email "${{ secrets.ACTION_USER_EMAIL }}"
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
+          go generate
           go test -v ./...
 
   gitconvex-build:
diff --git a/.gitignore b/.gitignore
index 4db4c48..5eeb66d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ gitclient
 /*.dll
 gitconvex
 gitconvex-server
+/local_env_set.sh
diff --git a/tests/beforeAll_git_clone_test.go b/tests/beforeAll_git_clone_test.go
index 15fff61..90ccd6c 100644
--- a/tests/beforeAll_git_clone_test.go
+++ b/tests/beforeAll_git_clone_test.go
@@ -4,13 +4,15 @@ import (
 	"github.com/neel1996/gitconvex/git"
 	"github.com/sirupsen/logrus"
 	"os"
+	"strconv"
 	"testing"
 )
 
 var TestRepo string
+var logger *logrus.Logger
 
 func TestMain(m *testing.M) {
-	logger := logrus.New()
+	logger = logrus.New()
 	TestRepo = os.Getenv("GITCONVEX_TEST_REPO")
 	if TestRepo == "" {
 		logger.Error("No test repo passed. Set GITCONVEX_TEST_REPO to a git directory to run integration tests")
@@ -35,4 +37,19 @@ func TestMain(m *testing.M) {
 
 	logger.Info("Initiating integration tests")
 	m.Run()
+	tearDownTests()
+}
+
+func tearDownTests() {
+	removeFlag, _ := strconv.ParseBool(os.Getenv("GITCONVEX_DELETE_TEST_REPO"))
+	if !removeFlag {
+		logger.Error("Test repo will be retained. If you use the same test repo again then the tests will fail during cloning stage")
+		return
+	}
+
+	err := os.RemoveAll(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		logger.Error(err)
+		return
+	}
 }
diff --git a/utils/env_file_handler.go b/utils/env_file_handler.go
index 7713b3c..0a8b7d9 100644
--- a/utils/env_file_handler.go
+++ b/utils/env_file_handler.go
@@ -42,6 +42,7 @@ func EnvConfigValidator() error {
 func EnvConfigFileReader() *EnvConfig {
 	cwd, cwdErr := DefaultDirSetup()
 	if cwdErr != nil {
+		logger.Log(cwdErr.Error(), global.StatusError)
 		return nil
 	}
 

From 8cf090fa63194319301cf4860f28bf35ad17e6fa Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 13 Jun 2021 23:42:10 +0530
Subject: [PATCH 003/148] refactor checkout function with new object generation
 instead of public struct based invokation

---
 git/git_branch_checkout.go | 218 +++++++++++++++++++++++--------------
 graph/schema.resolvers.go  |   7 +-
 2 files changed, 139 insertions(+), 86 deletions(-)

diff --git a/git/git_branch_checkout.go b/git/git_branch_checkout.go
index 9c1e8be..c981976 100644
--- a/git/git_branch_checkout.go
+++ b/git/git_branch_checkout.go
@@ -1,28 +1,35 @@
 package git
 
 import (
+	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
-	"go/types"
 	"strings"
 )
 
-type BranchCheckoutInterface interface {
+type BranchCheckout interface {
 	CheckoutBranch() string
 }
 
-type BranchCheckoutInputs struct {
+type branchCheckout struct {
 	Repo       *git2go.Repository
 	BranchName string
 }
 
-func returnCheckoutError(err error) string {
+type validatedBranchDetails struct {
+	branchName          string
+	referenceBranchName string
+	remoteBranchName    string
+	isRemoteBranch      bool
+}
+
+func branchCheckoutError(err error) string {
 	logger.Log(err.Error(), global.StatusError)
 	return global.BranchCheckoutError
 }
 
-func checkCheckoutError(err error) bool {
+func checkErrorAndPanic(err error) bool {
 	if err != nil {
 		logger.Log(err.Error(), global.StatusError)
 		panic(err)
@@ -32,11 +39,9 @@ func checkCheckoutError(err error) bool {
 }
 
 // CheckoutBranch checks out the branchName received as argument
-func (inputs BranchCheckoutInputs) CheckoutBranch() string {
-	var isRemoteBranch bool
-	var referenceBranchName string
-	var remoteBranchName string
+func (b branchCheckout) CheckoutBranch() string {
 	var errStatus bool
+	branchName := b.BranchName
 
 	defer func() string {
 		if r := recover(); r != nil {
@@ -46,92 +51,145 @@ func (inputs BranchCheckoutInputs) CheckoutBranch() string {
 		return global.BranchCheckoutError
 	}()
 
-	repo := inputs.Repo
-	branchName := inputs.BranchName
+	branchDetails := b.validateAndSetBranchDetails(branchName)
 
-	if strings.Contains(branchName, "remotes/") {
-		singleBranchName := strings.Split(branchName, "/")
-		referenceBranchName = "refs/heads/" + singleBranchName[len(singleBranchName)-1]
-		remoteBranchSplit := strings.Split(branchName, "remotes/")
-		remoteBranchName = remoteBranchSplit[len(remoteBranchSplit)-1]
-		branchName = singleBranchName[len(singleBranchName)-1]
-		isRemoteBranch = true
+	if branchDetails.isRemoteBranch {
+		errStatus = b.checkoutRemoteBranch(branchDetails)
+	}
+
+	errStatus = b.checkoutLocalBranch(branchDetails)
+
+	if errStatus {
+		return global.BranchCheckoutError
 	} else {
-		referenceBranchName = "refs/heads/" + branchName
+		logger.Log(fmt.Sprintf("Current branch checked out to -> %s", branchName), global.StatusInfo)
+		return fmt.Sprintf("Head checked out to branch - %v", branchName)
 	}
+}
+
+func (b branchCheckout) checkoutRemoteBranch(branchDetails validatedBranchDetails) bool {
+	var errStatus bool
+	branchName := b.BranchName
+	repo := b.Repo
 
-	if isRemoteBranch {
-		logger.Log(fmt.Sprintf("Branch - %s is a remote branch. Trying with intermediate remote fetch!", branchName), global.StatusWarning)
-
-		remoteBranch, remoteBranchErr := repo.LookupBranch(remoteBranchName, git2go.BranchRemote)
-		errStatus = checkCheckoutError(remoteBranchErr)
-
-		remoteHead := remoteBranch.Target()
-
-		remoteCommit, remoteCommitErr := repo.LookupCommit(remoteHead)
-		errStatus = checkCheckoutError(remoteCommitErr)
-
-		remoteTree, remoteTreeErr := remoteCommit.Tree()
-		errStatus = checkCheckoutError(remoteTreeErr)
-
-		checkoutErr := repo.CheckoutTree(remoteTree, &git2go.CheckoutOptions{Strategy: git2go.CheckoutSafe})
-		errStatus = checkCheckoutError(checkoutErr)
-
-		_, localLookupErr := repo.LookupBranch(branchName, git2go.BranchLocal)
-		if localLookupErr != nil {
-			logger.Log(localLookupErr.Error(), global.StatusError)
-
-			var addBranch AddBranch
-			addBranch = NewAddBranch(repo, branchName, false, remoteCommit)
-
-			branchCreateStatus := addBranch.AddBranch()
-			if branchCreateStatus != global.BranchAddError {
-				err := repo.SetHead(referenceBranchName)
-				if err != nil {
-					return returnCheckoutError(err)
-				} else {
-					return fmt.Sprintf("Head checked out to branch - %v", branchName)
-				}
-			} else {
-				return returnCheckoutError(types.Error{Msg: "Branch creation failed"})
-			}
-		} else {
-			err := repo.SetHead(referenceBranchName)
-			if err != nil {
-				return returnCheckoutError(err)
-			} else {
-				return fmt.Sprintf("Head checked out to branch - %v", branchName)
-			}
+	logger.Log(fmt.Sprintf("Branch - %s is a remote branch. Trying with intermediate remote fetch!", branchName), global.StatusWarning)
+
+	remoteBranch, remoteBranchErr := repo.LookupBranch(branchDetails.remoteBranchName, git2go.BranchRemote)
+	errStatus = checkErrorAndPanic(remoteBranchErr)
+
+	remoteHead := remoteBranch.Target()
+
+	remoteCommit, remoteCommitErr := repo.LookupCommit(remoteHead)
+	errStatus = checkErrorAndPanic(remoteCommitErr)
+
+	remoteTree, remoteTreeErr := remoteCommit.Tree()
+	errStatus = checkErrorAndPanic(remoteTreeErr)
+
+	checkoutErr := repo.CheckoutTree(remoteTree, &git2go.CheckoutOptions{Strategy: git2go.CheckoutSafe})
+	errStatus = checkErrorAndPanic(checkoutErr)
+
+	_, localLookupErr := repo.LookupBranch(branchName, git2go.BranchLocal)
+	if localLookupErr != nil {
+		logger.Log(localLookupErr.Error(), global.StatusError)
+		if err := addAndCheckoutNewBranch(repo, branchName, remoteCommit, branchDetails); err != nil {
+			return true
 		}
+		return errStatus
+	}
+
+	if err := repo.SetHead(branchDetails.referenceBranchName); err != nil {
+		branchCheckoutError(err)
+		return errStatus
 	}
 
+	return errStatus
+}
+
+func (b branchCheckout) checkoutLocalBranch(branchDetails validatedBranchDetails) bool {
+	errStatus := false
+	repo := b.Repo
+	branchName := b.BranchName
+
 	branch, branchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
-	errStatus = checkCheckoutError(branchErr)
+	errStatus = checkErrorAndPanic(branchErr)
 
 	topCommit, _ := repo.LookupCommit(branch.Target())
-	if topCommit != nil {
-		tree, treeErr := topCommit.Tree()
-		errStatus = checkCheckoutError(treeErr)
+	if topCommit == nil {
+		return true
+	}
 
-		checkoutErr := repo.CheckoutTree(tree, &git2go.CheckoutOptions{
-			Strategy:       git2go.CheckoutSafe,
-			DisableFilters: false,
-		})
+	tree, treeErr := topCommit.Tree()
+	errStatus = checkErrorAndPanic(treeErr)
 
-		if checkoutErr != nil {
-			return returnCheckoutError(checkoutErr)
-		}
+	checkoutErr := repo.CheckoutTree(tree, &git2go.CheckoutOptions{
+		Strategy:       git2go.CheckoutSafe,
+		DisableFilters: false,
+	})
 
-		err := repo.SetHead(referenceBranchName)
-		if err != nil {
-			return returnCheckoutError(err)
-		}
+	if checkoutErr != nil {
+		branchCheckoutError(checkoutErr)
+		return true
 	}
 
-	if errStatus {
-		return global.BranchCheckoutError
+	err := repo.SetHead(branchDetails.referenceBranchName)
+	if err != nil {
+		branchCheckoutError(err)
+		return true
+	}
+	return errStatus
+}
+
+func addAndCheckoutNewBranch(repo *git2go.Repository, branchName string, remoteCommit *git2go.Commit, branchDetails validatedBranchDetails) error {
+	var addBranch AddBranch
+	addBranch = NewAddBranch(repo, branchName, false, remoteCommit)
+
+	branchCreateStatus := addBranch.AddBranch()
+	if branchCreateStatus == global.BranchAddError {
+		err := errors.New("branch creation failed")
+		branchCheckoutError(err)
+		return err
+	}
+
+	if err := repo.SetHead(branchDetails.referenceBranchName); err != nil {
+		branchCheckoutError(err)
+		return err
+	}
+
+	return nil
+}
+
+func (b branchCheckout) validateAndSetBranchDetails(branchName string) validatedBranchDetails {
+	var (
+		referenceBranchName string
+		remoteBranchName    string
+		isRemoteBranch      bool
+	)
+
+	if strings.Contains(branchName, "remotes/") {
+		referenceBranchName = "refs/heads/" + splitAndReturnBranchName("/", branchName)
+		remoteBranchName = splitAndReturnBranchName("remotes/", branchName)
+		branchName = splitAndReturnBranchName("/", branchName)
+		isRemoteBranch = true
 	} else {
-		logger.Log(fmt.Sprintf("Current branch checked out to -> %s", branchName), global.StatusInfo)
-		return fmt.Sprintf("Head checked out to branch - %v", branchName)
+		referenceBranchName = "refs/heads/" + branchName
+	}
+
+	return validatedBranchDetails{
+		branchName:          branchName,
+		referenceBranchName: referenceBranchName,
+		remoteBranchName:    remoteBranchName,
+		isRemoteBranch:      isRemoteBranch,
+	}
+}
+
+func splitAndReturnBranchName(delimiter string, branchName string) string {
+	splitString := strings.Split(branchName, delimiter)
+	return splitString[len(splitString)-1]
+}
+
+func NewBranchCheckout(repo *git2go.Repository, branchName string) BranchCheckout {
+	return branchCheckout{
+		Repo:       repo,
+		BranchName: branchName,
 	}
 }
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index cbade0d..eac012d 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -62,12 +62,7 @@ func (r *mutationResolver) CheckoutBranch(ctx context.Context, repoID string, br
 		return global.BranchCheckoutError, nil
 	}
 
-	var checkoutObject git.BranchCheckoutInterface
-	checkoutObject = git.BranchCheckoutInputs{
-		Repo:       repo.GitRepo,
-		BranchName: branchName,
-	}
-	return checkoutObject.CheckoutBranch(), nil
+	return git.NewBranchCheckout(repo.GitRepo, branchName).CheckoutBranch(), nil
 }
 
 func (r *mutationResolver) DeleteBranch(ctx context.Context, repoID string, branchName string, forceFlag bool) (*model.BranchDeleteStatus, error) {

From 46405331f07fcbeb455a9f55392b20eb2b0abd5a Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 14 Jun 2021 23:59:08 +0530
Subject: [PATCH 004/148] refactor branch compare function to clean up complex
 code

---
 git/git_branch_compare.go | 117 +++++++++++++++++++++++---------------
 1 file changed, 71 insertions(+), 46 deletions(-)

diff --git a/git/git_branch_compare.go b/git/git_branch_compare.go
index f16cf0f..2869668 100644
--- a/git/git_branch_compare.go
+++ b/git/git_branch_compare.go
@@ -28,19 +28,19 @@ func returnBranchCompareError(errString string) []*model.BranchCompareResults {
 
 // CompareBranch compares two branches and returns the commits which are different from each other
 // The function uses the git client to fetch the results as go-git lacks this feature
-func (inputs BranchCompareInputs) CompareBranch() []*model.BranchCompareResults {
+func (b BranchCompareInputs) CompareBranch() []*model.BranchCompareResults {
 	var diffCommits []*model.BranchCompareResults
-	var commits []model.GitCommits
-	repo := inputs.Repo
+	var filteredCommits []model.GitCommits
+	repo := b.Repo
 
-	baseBranch, baseBranchErr := repo.LookupBranch(inputs.BaseBranch, git2go.BranchLocal)
-	compareBranch, compareBranchErr := repo.LookupBranch(inputs.DiffBranch, git2go.BranchLocal)
+	baseBranch, baseBranchErr := repo.LookupBranch(b.BaseBranch, git2go.BranchLocal)
+	compareBranch, compareBranchErr := repo.LookupBranch(b.DiffBranch, git2go.BranchLocal)
 
 	if baseBranchErr != nil || compareBranchErr != nil {
 		return returnBranchCompareError("Unable to lookup target branches from the repo")
 	}
-	compareResult := baseBranch.Cmp(compareBranch.Reference)
 
+	compareResult := baseBranch.Cmp(compareBranch.Reference)
 	if compareResult == 0 {
 		return returnBranchCompareError("There are no difference between both the branches")
 	}
@@ -55,27 +55,63 @@ func (inputs BranchCompareInputs) CompareBranch() []*model.BranchCompareResults
 		return returnBranchCompareError("Branch head is NIL")
 	}
 
-	var baseNext *git2go.Commit
-	var compareNext *git2go.Commit
 	baseBranchMap := make(map[string]*git2go.Commit)
 	compareBranchMap := make(map[string]*git2go.Commit)
 
-	if baseHead.ParentCount() > 0 {
-		baseNext = baseHead.Parent(0)
-		for baseNext != nil {
-			baseBranchMap[baseNext.Id().String()] = baseNext
-			baseNext = baseNext.Parent(0)
+	baseBranchMap = getParentCommits(baseHead)
+	compareBranchMap = getParentCommits(compareHead)
+
+	filteredCommits = filterDifferingCommits(compareBranchMap, baseBranchMap)
+	commitMap := generateCommitMaps(filteredCommits)
+	diffCommits = sortCommitsBasedOnDate(commitMap, diffCommits)
+
+	return diffCommits
+}
+
+// Organizing differing commits based on date
+func generateCommitMaps(filteredCommits []model.GitCommits) map[string][]*model.GitCommits {
+	var commitMap = make(map[string][]*model.GitCommits)
+	var commitHashMap = make(map[string]bool)
+
+	for i := range filteredCommits {
+		selectedDate := *filteredCommits[i].CommitTime
+
+		j := i
+		for j < len(filteredCommits) {
+			if shouldBreakLoop(selectedDate, filteredCommits, j, commitHashMap) {
+				break
+			}
+
+			if commitMap[selectedDate] != nil {
+				tempCommit := commitMap[selectedDate]
+				tempCommit = append(tempCommit, &filteredCommits[j])
+				commitMap[selectedDate] = tempCommit
+				commitHashMap[*filteredCommits[j].Hash] = true
+			} else {
+				tempCommit := []*model.GitCommits{&filteredCommits[j]}
+				commitMap[selectedDate] = tempCommit
+				commitHashMap[*filteredCommits[j].Hash] = true
+			}
+			j++
 		}
 	}
+	return commitMap
+}
 
-	if compareHead.ParentCount() > 0 {
-		compareNext = compareHead.Parent(0)
-		for compareNext != nil {
-			compareBranchMap[compareNext.Id().String()] = compareNext
-			compareNext = compareNext.Parent(0)
-		}
+func shouldBreakLoop(selectedDate string, filteredCommits []model.GitCommits, iterator int, commitHashMap map[string]bool) bool {
+	if selectedDate != *filteredCommits[iterator].CommitTime {
+		return true
+	}
+
+	if len(commitHashMap) > 0 && commitHashMap[*filteredCommits[iterator].Hash] {
+		return true
 	}
 
+	return false
+}
+
+func filterDifferingCommits(compareBranchMap map[string]*git2go.Commit, baseBranchMap map[string]*git2go.Commit) []model.GitCommits {
+	var commits []model.GitCommits
 	for commitHash, commit := range compareBranchMap {
 		if baseBranchMap[commitHash] == nil {
 			hash := commit.Id().String()
@@ -91,37 +127,27 @@ func (inputs BranchCompareInputs) CompareBranch() []*model.BranchCompareResults
 			})
 		}
 	}
+	return commits
+}
 
-	// Organizing differing commits based on date
-	var commitMap = make(map[string][]*model.GitCommits)
-	var tempCommitHashMap = make(map[string]bool)
+func getParentCommits(head *git2go.Commit) map[string]*git2go.Commit {
+	var next *git2go.Commit
+	commitMap := make(map[string]*git2go.Commit)
 
-	for i := range commits {
-		selectedDate := *commits[i].CommitTime
+	if head.ParentCount() == 0 {
+		return commitMap
+	}
 
-		j := i
-		for j < len(commits) {
-			if selectedDate == *commits[j].CommitTime {
-				if len(tempCommitHashMap) > 0 && tempCommitHashMap[*commits[j].Hash] {
-					break
-				}
-				if commitMap[selectedDate] != nil {
-					tempCommit := commitMap[selectedDate]
-					tempCommit = append(tempCommit, &commits[j])
-					commitMap[selectedDate] = tempCommit
-					tempCommitHashMap[*commits[j].Hash] = true
-				} else {
-					tempCommit := []*model.GitCommits{&commits[j]}
-					commitMap[selectedDate] = tempCommit
-					tempCommitHashMap[*commits[j].Hash] = true
-				}
-			} else {
-				break
-			}
-			j++
-		}
+	next = head.Parent(0)
+	for next != nil {
+		commitMap[next.Id().String()] = next
+		next = next.Parent(0)
 	}
 
+	return commitMap
+}
+
+func sortCommitsBasedOnDate(commitMap map[string][]*model.GitCommits, diffCommits []*model.BranchCompareResults) []*model.BranchCompareResults {
 	// Sorting commits in reverse chronological order of date
 	var keys []string
 	for k := range commitMap {
@@ -137,6 +163,5 @@ func (inputs BranchCompareInputs) CompareBranch() []*model.BranchCompareResults
 			Commits: commitMap[date],
 		})
 	}
-
 	return diffCommits
 }

From 2283e731947703751d3af481cfc82fb25f80b86b Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 15 Jun 2021 17:53:00 +0530
Subject: [PATCH 005/148] replace public struct with new function for branch
 compare

---
 git/git_branch_compare.go | 14 +++++++++++---
 graph/schema.resolvers.go | 10 ++--------
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/git/git_branch_compare.go b/git/git_branch_compare.go
index 2869668..26945c9 100644
--- a/git/git_branch_compare.go
+++ b/git/git_branch_compare.go
@@ -8,11 +8,11 @@ import (
 	"strings"
 )
 
-type BranchCompareInterface interface {
+type BranchCompare interface {
 	CompareBranch() []*model.BranchCompareResults
 }
 
-type BranchCompareInputs struct {
+type branchCompare struct {
 	Repo       *git2go.Repository
 	BaseBranch string
 	DiffBranch string
@@ -28,7 +28,7 @@ func returnBranchCompareError(errString string) []*model.BranchCompareResults {
 
 // CompareBranch compares two branches and returns the commits which are different from each other
 // The function uses the git client to fetch the results as go-git lacks this feature
-func (b BranchCompareInputs) CompareBranch() []*model.BranchCompareResults {
+func (b branchCompare) CompareBranch() []*model.BranchCompareResults {
 	var diffCommits []*model.BranchCompareResults
 	var filteredCommits []model.GitCommits
 	repo := b.Repo
@@ -165,3 +165,11 @@ func sortCommitsBasedOnDate(commitMap map[string][]*model.GitCommits, diffCommit
 	}
 	return diffCommits
 }
+
+func NewBranchCompare(repo *git2go.Repository, baseBranch string, diffBranch string) BranchCompare {
+	return branchCompare{
+		Repo:       repo,
+		BaseBranch: baseBranch,
+		DiffBranch: diffBranch,
+	}
+}
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index eac012d..eee9a4e 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -669,14 +669,8 @@ func (r *queryResolver) BranchCompare(ctx context.Context, repoID string, baseBr
 			},
 		}, nil
 	}
-
-	var branchCompareObject git.BranchCompareInterface
-	branchCompareObject = git.BranchCompareInputs{
-		Repo:       repo.GitRepo,
-		BaseBranch: baseBranch,
-		DiffBranch: compareBranch,
-	}
-	return branchCompareObject.CompareBranch(), nil
+ 
+	return git.NewBranchCompare(repo.GitRepo, baseBranch, compareBranch).CompareBranch(), nil
 }
 
 func (r *queryResolver) GetRemote(ctx context.Context, repoID string) ([]*model.RemoteDetails, error) {

From b896c38254262a25efad8610ee472b6058f5d805 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 16 Jun 2021 23:52:39 +0530
Subject: [PATCH 006/148] create new branch ops interface for handling all
 branch operations

---
 git/branch/branch.go                    | 59 +++++++++++++++++++++++++
 git/{ => branch}/git_branch_add.go      |  2 +-
 git/{ => branch}/git_branch_checkout.go |  2 +-
 git/{ => branch}/git_branch_compare.go  |  2 +-
 graph/schema.resolvers.go               | 19 +++++---
 tests/git_branch_add_test.go            |  3 +-
 tests/git_branch_delete_test.go         |  3 +-
 7 files changed, 79 insertions(+), 11 deletions(-)
 create mode 100644 git/branch/branch.go
 rename git/{ => branch}/git_branch_add.go (99%)
 rename git/{ => branch}/git_branch_checkout.go (99%)
 rename git/{ => branch}/git_branch_compare.go (99%)

diff --git a/git/branch/branch.go b/git/branch/branch.go
new file mode 100644
index 0000000..cda41e1
--- /dev/null
+++ b/git/branch/branch.go
@@ -0,0 +1,59 @@
+package branch
+
+import (
+	"errors"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+var logger global.Logger
+
+type Branch interface {
+	GitAddBranch() (string, error)
+	GitCheckoutBranch() (string, error)
+	GitCompareBranches() ([]*model.BranchCompareResults, error)
+}
+
+type branch struct {
+	addBranch       AddBranch
+	checkoutBranch  BranchCheckout
+	compareBranches BranchCompare
+}
+
+func (b branch) GitAddBranch() (string, error) {
+	addBranchResult := b.addBranch.AddBranch()
+
+	if addBranchResult == global.BranchAddError {
+		return "", errors.New(global.BranchAddError)
+	}
+
+	return addBranchResult, nil
+}
+
+func (b branch) GitCheckoutBranch() (string, error) {
+	checkoutBranchResult := b.checkoutBranch.CheckoutBranch()
+
+	if checkoutBranchResult == global.BranchCheckoutError {
+		return "", errors.New(global.BranchCheckoutError)
+	}
+
+	return checkoutBranchResult, nil
+}
+
+func (b branch) GitCompareBranches() ([]*model.BranchCompareResults, error) {
+	branchDiff := b.compareBranches.CompareBranch()
+
+	if len(branchDiff) == 0 {
+		return []*model.BranchCompareResults{}, errors.New("no difference between the two branches")
+	}
+
+	return branchDiff, nil
+}
+
+func NewBranchOperation(addBranch AddBranch, branchCheckout BranchCheckout, branchCompare BranchCompare) Branch {
+	return branch{
+		addBranch:       addBranch,
+		checkoutBranch:  branchCheckout,
+		compareBranches: branchCompare,
+	}
+}
diff --git a/git/git_branch_add.go b/git/branch/git_branch_add.go
similarity index 99%
rename from git/git_branch_add.go
rename to git/branch/git_branch_add.go
index a16e63e..4560d13 100644
--- a/git/git_branch_add.go
+++ b/git/branch/git_branch_add.go
@@ -1,4 +1,4 @@
-package git
+package branch
 
 import (
 	"fmt"
diff --git a/git/git_branch_checkout.go b/git/branch/git_branch_checkout.go
similarity index 99%
rename from git/git_branch_checkout.go
rename to git/branch/git_branch_checkout.go
index c981976..0ca7913 100644
--- a/git/git_branch_checkout.go
+++ b/git/branch/git_branch_checkout.go
@@ -1,4 +1,4 @@
-package git
+package branch
 
 import (
 	"errors"
diff --git a/git/git_branch_compare.go b/git/branch/git_branch_compare.go
similarity index 99%
rename from git/git_branch_compare.go
rename to git/branch/git_branch_compare.go
index 26945c9..61aea99 100644
--- a/git/git_branch_compare.go
+++ b/git/branch/git_branch_compare.go
@@ -1,4 +1,4 @@
-package git
+package branch
 
 import (
 	git2go "github.com/libgit2/git2go/v31"
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index eee9a4e..e14f180 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -5,6 +5,7 @@ package graph
 
 import (
 	"context"
+	"github.com/neel1996/gitconvex/git/branch"
 
 	"github.com/neel1996/gitconvex/api"
 	"github.com/neel1996/gitconvex/git"
@@ -42,9 +43,10 @@ func (r *mutationResolver) AddBranch(ctx context.Context, repoID string, branchN
 		return global.BranchAddError, nil
 	}
 
-	var addBranch git.AddBranch
-	addBranch = git.NewAddBranch(repo.GitRepo, branchName, false, nil)
-	return addBranch.AddBranch(), nil
+	addBranch := branch.NewAddBranch(repo.GitRepo, branchName, false, nil)
+	b := branch.NewBranchOperation(addBranch, nil, nil)
+
+	return b.GitAddBranch()
 }
 
 func (r *mutationResolver) CheckoutBranch(ctx context.Context, repoID string, branchName string) (string, error) {
@@ -62,7 +64,10 @@ func (r *mutationResolver) CheckoutBranch(ctx context.Context, repoID string, br
 		return global.BranchCheckoutError, nil
 	}
 
-	return git.NewBranchCheckout(repo.GitRepo, branchName).CheckoutBranch(), nil
+	checkOutBranch := branch.NewBranchCheckout(repo.GitRepo, branchName)
+	b := branch.NewBranchOperation(nil, checkOutBranch, nil)
+
+	return b.GitCheckoutBranch()
 }
 
 func (r *mutationResolver) DeleteBranch(ctx context.Context, repoID string, branchName string, forceFlag bool) (*model.BranchDeleteStatus, error) {
@@ -669,8 +674,10 @@ func (r *queryResolver) BranchCompare(ctx context.Context, repoID string, baseBr
 			},
 		}, nil
 	}
- 
-	return git.NewBranchCompare(repo.GitRepo, baseBranch, compareBranch).CompareBranch(), nil
+
+	branchCompare := branch.NewBranchCompare(repo.GitRepo, baseBranch, compareBranch)
+	b := branch.NewBranchOperation(nil, nil, branchCompare)
+	return b.GitCompareBranches()
 }
 
 func (r *queryResolver) GetRemote(ctx context.Context, repoID string) ([]*model.RemoteDetails, error) {
diff --git a/tests/git_branch_add_test.go b/tests/git_branch_add_test.go
index 644d02b..6a261da 100644
--- a/tests/git_branch_add_test.go
+++ b/tests/git_branch_add_test.go
@@ -3,6 +3,7 @@ package tests
 import (
 	git "github.com/libgit2/git2go/v31"
 	git2 "github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/stretchr/testify/assert"
 	"testing"
 )
@@ -26,7 +27,7 @@ func TestAddBranch(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			obj := git2.NewAddBranch(tt.args.repo, tt.args.branchName, false, nil)
+			obj := branch.NewAddBranch(tt.args.repo, tt.args.branchName, false, nil)
 			got := obj.AddBranch()
 			assert.Equal(t, tt.want, got)
 
diff --git a/tests/git_branch_delete_test.go b/tests/git_branch_delete_test.go
index b4d6b19..6d44e69 100644
--- a/tests/git_branch_delete_test.go
+++ b/tests/git_branch_delete_test.go
@@ -3,6 +3,7 @@ package tests
 import (
 	git "github.com/libgit2/git2go/v31"
 	git2 "github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/stretchr/testify/assert"
 	"testing"
@@ -33,7 +34,7 @@ func TestDeleteBranch(t *testing.T) {
 				BranchName: tt.args.branchName,
 			}
 
-			git2.NewAddBranch(r, "test", false, nil).AddBranch()
+			branch.NewAddBranch(r, "test", false, nil).AddBranch()
 
 			got := testObj.DeleteBranch()
 			assert.Equal(t, tt.want, got)

From 434916375b3036f32ec6c8801332e6c8dc0ae241 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 17 Jun 2021 23:18:49 +0530
Subject: [PATCH 007/148] update branch operation handler to accept operations
 in struct instead of new creator function

---
 git/branch/branch.go              | 28 ++++++++++------------------
 git/branch/git_branch_add.go      |  5 ++---
 git/branch/git_branch_checkout.go |  7 +++----
 git/branch/git_branch_compare.go  |  4 ++--
 graph/schema.resolvers.go         | 14 +++++++++-----
 5 files changed, 26 insertions(+), 32 deletions(-)

diff --git a/git/branch/branch.go b/git/branch/branch.go
index cda41e1..4fef3ca 100644
--- a/git/branch/branch.go
+++ b/git/branch/branch.go
@@ -14,14 +14,14 @@ type Branch interface {
 	GitCompareBranches() ([]*model.BranchCompareResults, error)
 }
 
-type branch struct {
-	addBranch       AddBranch
-	checkoutBranch  BranchCheckout
-	compareBranches BranchCompare
+type Operation struct {
+	Add      Add
+	Checkout Checkout
+	Compare  Compare
 }
 
-func (b branch) GitAddBranch() (string, error) {
-	addBranchResult := b.addBranch.AddBranch()
+func (b Operation) GitAddBranch() (string, error) {
+	addBranchResult := b.Add.AddBranch()
 
 	if addBranchResult == global.BranchAddError {
 		return "", errors.New(global.BranchAddError)
@@ -30,8 +30,8 @@ func (b branch) GitAddBranch() (string, error) {
 	return addBranchResult, nil
 }
 
-func (b branch) GitCheckoutBranch() (string, error) {
-	checkoutBranchResult := b.checkoutBranch.CheckoutBranch()
+func (b Operation) GitCheckoutBranch() (string, error) {
+	checkoutBranchResult := b.Checkout.CheckoutBranch()
 
 	if checkoutBranchResult == global.BranchCheckoutError {
 		return "", errors.New(global.BranchCheckoutError)
@@ -40,8 +40,8 @@ func (b branch) GitCheckoutBranch() (string, error) {
 	return checkoutBranchResult, nil
 }
 
-func (b branch) GitCompareBranches() ([]*model.BranchCompareResults, error) {
-	branchDiff := b.compareBranches.CompareBranch()
+func (b Operation) GitCompareBranches() ([]*model.BranchCompareResults, error) {
+	branchDiff := b.Compare.CompareBranch()
 
 	if len(branchDiff) == 0 {
 		return []*model.BranchCompareResults{}, errors.New("no difference between the two branches")
@@ -49,11 +49,3 @@ func (b branch) GitCompareBranches() ([]*model.BranchCompareResults, error) {
 
 	return branchDiff, nil
 }
-
-func NewBranchOperation(addBranch AddBranch, branchCheckout BranchCheckout, branchCompare BranchCompare) Branch {
-	return branch{
-		addBranch:       addBranch,
-		checkoutBranch:  branchCheckout,
-		compareBranches: branchCompare,
-	}
-}
diff --git a/git/branch/git_branch_add.go b/git/branch/git_branch_add.go
index 4560d13..fea195d 100644
--- a/git/branch/git_branch_add.go
+++ b/git/branch/git_branch_add.go
@@ -6,7 +6,7 @@ import (
 	"github.com/neel1996/gitconvex/global"
 )
 
-type AddBranch interface {
+type Add interface {
 	AddBranch() string
 }
 
@@ -17,7 +17,6 @@ type addBranch struct {
 	TargetCommit *git2go.Commit
 }
 
-// AddBranch adds a new branch to the target repo
 func (a addBranch) AddBranch() string {
 	targetCommit := a.TargetCommit
 	repo := a.Repo
@@ -58,7 +57,7 @@ func (a addBranch) validateTargetCommit(targetCommit *git2go.Commit, repo *git2g
 	return headCommit, false
 }
 
-func NewAddBranch(repo *git2go.Repository, branchName string, remoteSwitch bool, targetCommit *git2go.Commit) AddBranch {
+func NewAddBranch(repo *git2go.Repository, branchName string, remoteSwitch bool, targetCommit *git2go.Commit) Add {
 	return addBranch{
 		Repo:         repo,
 		BranchName:   branchName,
diff --git a/git/branch/git_branch_checkout.go b/git/branch/git_branch_checkout.go
index 0ca7913..b8fcdec 100644
--- a/git/branch/git_branch_checkout.go
+++ b/git/branch/git_branch_checkout.go
@@ -8,7 +8,7 @@ import (
 	"strings"
 )
 
-type BranchCheckout interface {
+type Checkout interface {
 	CheckoutBranch() string
 }
 
@@ -140,8 +140,7 @@ func (b branchCheckout) checkoutLocalBranch(branchDetails validatedBranchDetails
 }
 
 func addAndCheckoutNewBranch(repo *git2go.Repository, branchName string, remoteCommit *git2go.Commit, branchDetails validatedBranchDetails) error {
-	var addBranch AddBranch
-	addBranch = NewAddBranch(repo, branchName, false, remoteCommit)
+	addBranch := NewAddBranch(repo, branchName, false, remoteCommit)
 
 	branchCreateStatus := addBranch.AddBranch()
 	if branchCreateStatus == global.BranchAddError {
@@ -187,7 +186,7 @@ func splitAndReturnBranchName(delimiter string, branchName string) string {
 	return splitString[len(splitString)-1]
 }
 
-func NewBranchCheckout(repo *git2go.Repository, branchName string) BranchCheckout {
+func NewBranchCheckout(repo *git2go.Repository, branchName string) Checkout {
 	return branchCheckout{
 		Repo:       repo,
 		BranchName: branchName,
diff --git a/git/branch/git_branch_compare.go b/git/branch/git_branch_compare.go
index 61aea99..cee88fe 100644
--- a/git/branch/git_branch_compare.go
+++ b/git/branch/git_branch_compare.go
@@ -8,7 +8,7 @@ import (
 	"strings"
 )
 
-type BranchCompare interface {
+type Compare interface {
 	CompareBranch() []*model.BranchCompareResults
 }
 
@@ -166,7 +166,7 @@ func sortCommitsBasedOnDate(commitMap map[string][]*model.GitCommits, diffCommit
 	return diffCommits
 }
 
-func NewBranchCompare(repo *git2go.Repository, baseBranch string, diffBranch string) BranchCompare {
+func NewBranchCompare(repo *git2go.Repository, baseBranch string, diffBranch string) Compare {
 	return branchCompare{
 		Repo:       repo,
 		BaseBranch: baseBranch,
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index e14f180..3ff6092 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -44,8 +44,9 @@ func (r *mutationResolver) AddBranch(ctx context.Context, repoID string, branchN
 	}
 
 	addBranch := branch.NewAddBranch(repo.GitRepo, branchName, false, nil)
-	b := branch.NewBranchOperation(addBranch, nil, nil)
-
+	b := branch.Operation{
+		Add: addBranch,
+	}
 	return b.GitAddBranch()
 }
 
@@ -65,8 +66,9 @@ func (r *mutationResolver) CheckoutBranch(ctx context.Context, repoID string, br
 	}
 
 	checkOutBranch := branch.NewBranchCheckout(repo.GitRepo, branchName)
-	b := branch.NewBranchOperation(nil, checkOutBranch, nil)
-
+	b := branch.Operation{
+		Checkout: checkOutBranch,
+	}
 	return b.GitCheckoutBranch()
 }
 
@@ -676,7 +678,9 @@ func (r *queryResolver) BranchCompare(ctx context.Context, repoID string, baseBr
 	}
 
 	branchCompare := branch.NewBranchCompare(repo.GitRepo, baseBranch, compareBranch)
-	b := branch.NewBranchOperation(nil, nil, branchCompare)
+	b := branch.Operation{
+		Compare: branchCompare,
+	}
 	return b.GitCompareBranches()
 }
 

From 5cdc3cf5c6967d6886bfbf90225e5f8b21c04618 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 18 Jun 2021 00:00:20 +0530
Subject: [PATCH 008/148] include branch deletion to the common branch
 interface

---
 git/branch/branch.go            | 11 ++++++++
 git/branch/git_branch_delete.go | 47 +++++++++++++++++++++++++++++++++
 git/git_branch_delete.go        | 40 ----------------------------
 tests/git_branch_add_test.go    |  6 +----
 tests/git_branch_delete_test.go | 15 ++++++-----
 5 files changed, 67 insertions(+), 52 deletions(-)
 create mode 100644 git/branch/git_branch_delete.go
 delete mode 100644 git/git_branch_delete.go

diff --git a/git/branch/branch.go b/git/branch/branch.go
index 4fef3ca..fd332da 100644
--- a/git/branch/branch.go
+++ b/git/branch/branch.go
@@ -18,6 +18,7 @@ type Operation struct {
 	Add      Add
 	Checkout Checkout
 	Compare  Compare
+	Delete   Delete
 }
 
 func (b Operation) GitAddBranch() (string, error) {
@@ -49,3 +50,13 @@ func (b Operation) GitCompareBranches() ([]*model.BranchCompareResults, error) {
 
 	return branchDiff, nil
 }
+
+func (b Operation) GitDeleteBranch() (*model.BranchDeleteStatus, error) {
+	deleteStatus := b.Delete.DeleteBranch()
+
+	if deleteStatus.Status == global.BranchDeleteError {
+		return nil, errors.New("branch deletion failed")
+	}
+
+	return deleteStatus, nil
+}
diff --git a/git/branch/git_branch_delete.go b/git/branch/git_branch_delete.go
new file mode 100644
index 0000000..a5969ff
--- /dev/null
+++ b/git/branch/git_branch_delete.go
@@ -0,0 +1,47 @@
+package branch
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type Delete interface {
+	DeleteBranch() *model.BranchDeleteStatus
+}
+
+type deleteBranch struct {
+	Repo       *git2go.Repository
+	BranchName string
+}
+
+// DeleteBranch deletes a branch from the repo
+func (inputs deleteBranch) DeleteBranch() *model.BranchDeleteStatus {
+	repo := inputs.Repo
+	branchName := inputs.BranchName
+	branch, deleteBranchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
+
+	if deleteBranchErr != nil {
+		logger.Log(fmt.Sprintf("Failed to delete branch %s -> %v", branchName, deleteBranchErr.Error()), global.StatusError)
+		return &model.BranchDeleteStatus{Status: global.BranchDeleteError}
+	}
+
+	deleteErr := branch.Delete()
+	if deleteErr != nil {
+		logger.Log(fmt.Sprintf("Failed to delete branch %s -> %v", branchName, deleteErr.Error()), global.StatusError)
+		return &model.BranchDeleteStatus{Status: global.BranchDeleteError}
+	}
+
+	logger.Log(fmt.Sprintf("Branch - %s has been removed from the repo", branchName), global.StatusInfo)
+	return &model.BranchDeleteStatus{
+		Status: global.BranchDeleteSuccess,
+	}
+}
+
+func NewDeleteBranch(repo *git2go.Repository, branchName string) Delete {
+	return deleteBranch{
+		Repo:       repo,
+		BranchName: branchName,
+	}
+}
diff --git a/git/git_branch_delete.go b/git/git_branch_delete.go
deleted file mode 100644
index b311674..0000000
--- a/git/git_branch_delete.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-)
-
-type DeleteBranchInterface interface {
-	DeleteBranch() *model.BranchDeleteStatus
-}
-
-type DeleteBranchInputs struct {
-	Repo       *git2go.Repository
-	BranchName string
-}
-
-// DeleteBranch deletes a branch from the repo
-func (inputs DeleteBranchInputs) DeleteBranch() *model.BranchDeleteStatus {
-	repo := inputs.Repo
-	branchName := inputs.BranchName
-	deleteBranch, deleteBranchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
-
-	if deleteBranchErr != nil {
-		logger.Log(fmt.Sprintf("Failed to delete branch %s -> %v", branchName, deleteBranchErr.Error()), global.StatusError)
-		return &model.BranchDeleteStatus{Status: global.BranchDeleteError}
-	} else {
-		deleteErr := deleteBranch.Delete()
-		if deleteErr == nil {
-			logger.Log(fmt.Sprintf("Branch - %s has been removed from the repo", branchName), global.StatusInfo)
-			return &model.BranchDeleteStatus{
-				Status: global.BranchDeleteSuccess,
-			}
-		} else {
-			logger.Log(fmt.Sprintf("Failed to delete branch %s -> %v", branchName, deleteErr.Error()), global.StatusError)
-			return &model.BranchDeleteStatus{Status: global.BranchDeleteError}
-		}
-	}
-}
diff --git a/tests/git_branch_add_test.go b/tests/git_branch_add_test.go
index 6a261da..2cfbcd5 100644
--- a/tests/git_branch_add_test.go
+++ b/tests/git_branch_add_test.go
@@ -2,7 +2,6 @@ package tests
 
 import (
 	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
 	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/stretchr/testify/assert"
 	"testing"
@@ -31,10 +30,7 @@ func TestAddBranch(t *testing.T) {
 			got := obj.AddBranch()
 			assert.Equal(t, tt.want, got)
 
-			git2.DeleteBranchInputs{
-				Repo:       r,
-				BranchName: "test",
-			}.DeleteBranch()
+			_, _ = branch.Operation{Delete: branch.NewDeleteBranch(r, "test")}.GitDeleteBranch()
 		})
 	}
 }
diff --git a/tests/git_branch_delete_test.go b/tests/git_branch_delete_test.go
index 6d44e69..de4cec7 100644
--- a/tests/git_branch_delete_test.go
+++ b/tests/git_branch_delete_test.go
@@ -2,7 +2,6 @@ package tests
 
 import (
 	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
 	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/stretchr/testify/assert"
@@ -28,15 +27,17 @@ func TestDeleteBranch(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.DeleteBranchInterface
-			testObj = git2.DeleteBranchInputs{
-				Repo:       tt.args.repo,
-				BranchName: tt.args.branchName,
+			b := branch.Operation{
+				Delete: branch.NewDeleteBranch(r, "test"),
+				Add:    branch.NewAddBranch(r, "test", false, nil),
 			}
 
-			branch.NewAddBranch(r, "test", false, nil).AddBranch()
+			_, err := b.GitAddBranch()
+			assert.Nil(t, err)
 
-			got := testObj.DeleteBranch()
+			got, err := b.GitDeleteBranch()
+
+			assert.Nil(t, err)
 			assert.Equal(t, tt.want, got)
 		})
 	}

From 6a6187f2dd35c63474d5cf164509e846d3650d0d Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 18 Jun 2021 09:17:01 +0530
Subject: [PATCH 009/148] include branch list into the common branch interface

---
 api/repo_status.go            |  10 ++--
 git/branch/branch.go          |   6 ++
 git/branch/git_branch_list.go | 110 ++++++++++++++++++++++++++++++++++
 git/git_branch_list.go        |  86 --------------------------
 graph/schema.resolvers.go     |   9 ++-
 tests/git_branch_test.go      |  16 +++--
 6 files changed, 132 insertions(+), 105 deletions(-)
 create mode 100644 git/branch/git_branch_list.go
 delete mode 100644 git/git_branch_list.go

diff --git a/api/repo_status.go b/api/repo_status.go
index 5c508f8..216d066 100644
--- a/api/repo_status.go
+++ b/api/repo_status.go
@@ -2,6 +2,7 @@ package api
 
 import (
 	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/neel1996/gitconvex/utils"
@@ -10,12 +11,11 @@ import (
 
 // RepoStatus collects the basic details of the target repo and returns the consolidated result
 func RepoStatus(repoId string) *model.GitRepoStatusResults {
-	logger := global.Logger{}
 	logger.Log("Collecting repo status information", global.StatusInfo)
 
 	repoChan := make(chan git.RepoDetails)
 	remoteChan := make(chan git.RemoteDataModel)
-	branchChan := make(chan git.Branch)
+	branchChan := make(chan branch.ListOfBranches)
 	commitChan := make(chan git.AllCommitData)
 	trackedFileCountChan := make(chan int)
 
@@ -80,9 +80,9 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 		*remoteURL = *remotes[0]
 	}
 
-	var branchListObject git.BranchListInterface
-	branchListObject = git.BranchListInputs{Repo: repo}
-	go branchListObject.GetBranchList(branchChan)
+	branchListObj := branch.NewBranchListInterface(repo)
+	b := branch.Operation{List: branchListObj}
+	go b.GitListBranches(branchChan)
 
 	branchList := <-branchChan
 	currentBranch := &branchList.CurrentBranch
diff --git a/git/branch/branch.go b/git/branch/branch.go
index fd332da..71d6d0f 100644
--- a/git/branch/branch.go
+++ b/git/branch/branch.go
@@ -12,6 +12,7 @@ type Branch interface {
 	GitAddBranch() (string, error)
 	GitCheckoutBranch() (string, error)
 	GitCompareBranches() ([]*model.BranchCompareResults, error)
+	GitListBranches(chan ListOfBranches)
 }
 
 type Operation struct {
@@ -19,6 +20,7 @@ type Operation struct {
 	Checkout Checkout
 	Compare  Compare
 	Delete   Delete
+	List     List
 }
 
 func (b Operation) GitAddBranch() (string, error) {
@@ -60,3 +62,7 @@ func (b Operation) GitDeleteBranch() (*model.BranchDeleteStatus, error) {
 
 	return deleteStatus, nil
 }
+
+func (b Operation) GitListBranches(branchChannel chan ListOfBranches) {
+	b.List.ListBranches(branchChannel)
+}
diff --git a/git/branch/git_branch_list.go b/git/branch/git_branch_list.go
new file mode 100644
index 0000000..037e226
--- /dev/null
+++ b/git/branch/git_branch_list.go
@@ -0,0 +1,110 @@
+package branch
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/global"
+	"go/types"
+	"strings"
+)
+
+type List interface {
+	ListBranches(branchChan chan ListOfBranches)
+}
+
+type listBranch struct {
+	Repo            *git2go.Repository
+	localBranchList []*string
+	allBranchList   []*string
+}
+
+type ListOfBranches struct {
+	CurrentBranch string
+	BranchList    []*string
+	AllBranchList []*string
+}
+
+// ListBranches fetches all the branches from the target repository
+// The result will be returned as a struct with the current branch and all the available branches
+func (l listBranch) ListBranches(branchChan chan ListOfBranches) {
+	var currentBranch string
+	repo := l.Repo
+
+	defer close(branchChan)
+
+	head, headErr := repo.Head()
+
+	if headErr != nil {
+		logger.Log(fmt.Sprintf("Repo head is invalid -> %s", headErr.Error()), global.StatusError)
+		nilMsg := []string{"No Branches available", "Repo HEAD is nil"}
+		branchChan <- ListOfBranches{
+			BranchList:    []*string{&nilMsg[0]},
+			CurrentBranch: nilMsg[1],
+			AllBranchList: []*string{&nilMsg[0]},
+		}
+		return
+	}
+
+	currentBranch = getCurrentBranchName(head)
+
+	l.allBranchList = append(l.allBranchList, &currentBranch)
+	l.localBranchList = append(l.localBranchList, &currentBranch)
+
+	localBranchIterator, itrErr := repo.NewBranchIterator(git2go.BranchAll)
+
+	if itrErr == nil {
+		l.runBranchIterator(localBranchIterator, currentBranch)
+	}
+
+	branchChan <- ListOfBranches{
+		BranchList:    l.localBranchList,
+		CurrentBranch: currentBranch,
+		AllBranchList: l.allBranchList,
+	}
+}
+
+func (l listBranch) runBranchIterator(localBranchIterator *git2go.BranchIterator, currentBranch string) {
+	_ = localBranchIterator.ForEach(func(branch *git2go.Branch, branchType git2go.BranchType) error {
+		branchName, nameErr := branch.Name()
+		if nameErr != nil {
+			return types.Error{Msg: "branch iterator end"}
+		}
+
+		if !branch.IsTag() && !branch.IsNote() && branchName != currentBranch {
+			l.classifyRemoteAndLocalBranches(branch, branchName, currentBranch)
+		}
+		return nil
+	})
+}
+
+func (l listBranch) classifyRemoteAndLocalBranches(branch *git2go.Branch, branchName string, currentBranch string) {
+	if branch.IsRemote() && strings.Contains(branchName, "/") {
+		l.getRemoteBranchName(branchName, currentBranch)
+	} else {
+		l.allBranchList = append(l.allBranchList, &branchName)
+		l.localBranchList = append(l.localBranchList, &branchName)
+	}
+}
+
+func (l listBranch) getRemoteBranchName(branchName string, currentBranch string) {
+	splitString := strings.Split(branchName, "/")
+	splitBranch := splitString[len(splitString)-1]
+
+	if splitBranch != "HEAD" && splitBranch != currentBranch {
+		concatRemote := "remotes/" + strings.Join(splitString, "/")
+		l.allBranchList = append(l.allBranchList, &concatRemote)
+	}
+}
+
+func getCurrentBranchName(head *git2go.Reference) string {
+	branch := head.Name()
+	splitCurrentBranch := strings.Split(branch, "/")
+	branch = splitCurrentBranch[len(splitCurrentBranch)-1]
+	return branch
+}
+
+func NewBranchListInterface(repo *git2go.Repository) List {
+	return listBranch{
+		Repo: repo,
+	}
+}
diff --git a/git/git_branch_list.go b/git/git_branch_list.go
deleted file mode 100644
index 69acba1..0000000
--- a/git/git_branch_list.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"go/types"
-	"strings"
-)
-
-type BranchListInterface interface {
-	GetBranchList(branchChan chan Branch)
-}
-
-type BranchListInputs struct {
-	Repo *git2go.Repository
-}
-
-type Branch struct {
-	CurrentBranch string
-	BranchList    []*string
-	AllBranchList []*string
-}
-
-// GetBranchList fetches all the branches from the target repository
-// The result will be returned as a struct with the current branch and all the available branches
-func (inputs BranchListInputs) GetBranchList(branchChan chan Branch) {
-	var (
-		branches      []*string
-		allBranchList []*string
-	)
-	var currentBranch string
-	repo := inputs.Repo
-
-	if repo != nil {
-		head, headErr := repo.Head()
-
-		if headErr != nil {
-			logger.Log(fmt.Sprintf("Repo head is invalid -> %s", headErr.Error()), global.StatusError)
-			nilMsg := []string{"No Branches available", "Repo HEAD is nil", "No Branches Present"}
-			branchChan <- Branch{
-				BranchList:    []*string{&nilMsg[0]},
-				CurrentBranch: nilMsg[1],
-				AllBranchList: []*string{&nilMsg[2]},
-			}
-		} else {
-			currentBranch = head.Name()
-			splitCurrentBranch := strings.Split(currentBranch, "/")
-			currentBranch = splitCurrentBranch[len(splitCurrentBranch)-1]
-
-			allBranchList = append(allBranchList, &currentBranch)
-			branches = append(branches, &currentBranch)
-
-			localBranchIterator, itrErr := repo.NewBranchIterator(git2go.BranchAll)
-
-			if itrErr == nil {
-				_ = localBranchIterator.ForEach(func(branch *git2go.Branch, branchType git2go.BranchType) error {
-					branchName, nameErr := branch.Name()
-					if branch == nil {
-						return types.Error{Msg: "branch iterator end"}
-					}
-					if nameErr == nil && !branch.IsTag() && !branch.IsNote() && branchName != currentBranch {
-						if branch.IsRemote() && strings.Contains(branchName, "/") {
-							splitString := strings.Split(branchName, "/")
-							splitBranch := splitString[len(splitString)-1]
-							if splitBranch != "HEAD" && splitBranch != currentBranch {
-								concatRemote := "remotes/" + strings.Join(splitString, "/")
-								allBranchList = append(allBranchList, &concatRemote)
-							}
-						} else {
-							allBranchList = append(allBranchList, &branchName)
-							branches = append(branches, &branchName)
-						}
-					}
-					return nil
-				})
-			}
-			branchChan <- Branch{
-				BranchList:    branches,
-				CurrentBranch: currentBranch,
-				AllBranchList: allBranchList,
-			}
-		}
-	}
-	close(branchChan)
-}
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index 3ff6092..562a816 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -87,12 +87,11 @@ func (r *mutationResolver) DeleteBranch(ctx context.Context, repoID string, bran
 		}, nil
 	}
 
-	var deleteBranchObject git.DeleteBranchInterface
-	deleteBranchObject = git.DeleteBranchInputs{
-		Repo:       repo.GitRepo,
-		BranchName: branchName,
+	deleteBranch := branch.NewDeleteBranch(repo.GitRepo, branchName)
+	b := branch.Operation{
+		Delete: deleteBranch,
 	}
-	return deleteBranchObject.DeleteBranch(), nil
+	return b.GitDeleteBranch()
 }
 
 func (r *mutationResolver) FetchFromRemote(ctx context.Context, repoID string, remoteURL *string, remoteBranch *string) (*model.FetchResult, error) {
diff --git a/tests/git_branch_test.go b/tests/git_branch_test.go
index 748d2a8..b072101 100644
--- a/tests/git_branch_test.go
+++ b/tests/git_branch_test.go
@@ -2,18 +2,18 @@ package tests
 
 import (
 	"github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/stretchr/testify/assert"
 	"testing"
 )
 
 func TestGetBranchList(t *testing.T) {
-	b := make(chan git2.Branch)
+	b := make(chan branch.ListOfBranches)
 	r, _ := git.OpenRepository(TestRepo)
 
 	type args struct {
 		repo       *git.Repository
-		branchChan chan git2.Branch
+		branchChan chan branch.ListOfBranches
 	}
 	tests := []struct {
 		name string
@@ -21,16 +21,14 @@ func TestGetBranchList(t *testing.T) {
 	}{
 		{name: "Git branch list test case", args: struct {
 			repo       *git.Repository
-			branchChan chan git2.Branch
+			branchChan chan branch.ListOfBranches
 		}{repo: r, branchChan: b}},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.BranchListInterface
-			testObj = git2.BranchListInputs{
-				Repo: tt.args.repo,
-			}
-			go testObj.GetBranchList(tt.args.branchChan)
+			testObj := branch.NewBranchListInterface(tt.args.repo)
+			
+			go testObj.ListBranches(tt.args.branchChan)
 			branchList := <-tt.args.branchChan
 
 			cBranch := branchList.CurrentBranch

From 6d8dda32573e249c3e0e8c421aeff5cd5cfb4685 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 18 Jun 2021 23:52:40 +0530
Subject: [PATCH 010/148] add new build scripts to Makefile

---
 .gitignore                        |  3 ++
 Makefile                          | 64 +++++++++++++------------------
 build_scripts/build_server.sh     | 14 +++++++
 build_scripts/build_ui.sh         | 16 ++++++++
 git/branch/git_branch_add.go      | 22 +++++------
 git/branch/git_branch_checkout.go | 18 ++++-----
 git/branch/git_branch_compare.go  | 18 ++++-----
 git/branch/git_branch_delete.go   | 12 +++---
 git/branch/git_branch_list.go     |  6 +--
 9 files changed, 97 insertions(+), 76 deletions(-)
 create mode 100755 build_scripts/build_server.sh
 create mode 100755 build_scripts/build_ui.sh

diff --git a/.gitignore b/.gitignore
index 5eeb66d..8d9f721 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,9 @@
 build/
 .idea/
 database/
+ui/
+dist/
+
 env_config.json
 gitclient
 /*.exe
diff --git a/Makefile b/Makefile
index 51206dc..9988493 100644
--- a/Makefile
+++ b/Makefile
@@ -1,50 +1,38 @@
 get:
 	go get
+
 run:
 	go run server.go
+
 build-ui:
-	git clone https://github.com/neel1996/gitconvex-ui.git ui/
-	cd ui
-	npm install
-	export NODE_ENV=production
-	npm i -g create-react-app tailwindcss@1.6.0
-	npm run build:tailwind
-	npm run build
-	mv ./build ../
+	@./build_scripts/build_ui.sh
+
 build-server:
-	mkdir -p ./dist
-	go build -o ./dist
-
-build:
-	@echo "⚒️ Initiating gitconvex build"
-	@echo "🗑️ Cleaning up old directories"
-	@rm -rf ui/ dist/ build/
-	@echo "⏬ Cloning gitconvex react repo"
-	@git clone -q https://github.com/neel1996/gitconvex-ui.git ui/ && \
-	cd ui && \
-	echo "⏳ Installing UI dependencies..." && \
-	npm install --silent && \
-	export NODE_ENV=production && \
-	npm install tailwindcss postcss autoprefixer && \
-	npx tailwindcss build -o ./src/index.css -c ./src/tailwind.config.js && \
-	rm package-*.json && \
-	rm -rf .git/ && \
-	echo "🔧 Building react UI bundle" && \
-	npm run build && \
-	mv ./build ../ && \
-	cd .. && \
-	mkdir -p ./dist && \
-	mv build/ ./dist/ && \
-	mv ./dist/build ./dist/gitconvex-ui
-	echo "🚀 Building final go source with UI bundle" && \
-	go build -v -a -o ./dist && \
-	echo "Gitconvex build completed!" && \
-	mv ./dist/gitconvex-server ./dist/gitconvex 
-	@echo "Installing libs"
+	@./build_scripts/build_server.sh
+
+clean:
+	@echo "💨 Cleaning up previous build and bundles..."
+	@rm -rf ui/ dist/ gitconvex build/
+
+bundle:
+	@mkdir -p ./dist && \
+    mv ./build/ ./dist/ && \
+    mv ./dist/build ./dist/gitconvex-ui;
+
+pack:
+	cd ./dist && \
+	tar -cvzf gitconvex-$(GITCONVEX_VERSION).tar.gz .
+
+build: clean build-ui bundle build-server
 	@echo "✅ Gitconvex Build Completed successfully!"
 	@echo "📬 Use ./dist/gitconvex to start Gitconvex on port 9001"
 	@echo "📬 Try ./dist/gitconvex --port PORT_NUMBER to run gitconvex on the desired port"
+
 test:
-	go test -tags static -v ./...
+	mkdir -p testRepo
+	export GITCONVEX_TEST_REPO=$(pwd)/testRepo && export GITCONVEX_DEFAULT_PATH=$(pwd)/testRepo
+	cd $GITCONVEX_TEST_REPO
+	go test -v ./...
+
 start:
 	./dist/gitconvex
diff --git a/build_scripts/build_server.sh b/build_scripts/build_server.sh
new file mode 100755
index 0000000..ec042eb
--- /dev/null
+++ b/build_scripts/build_server.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+if [[ "$GITCONVEX_DEFAULT_PATH" == "" ]]; then
+  echo "Default path missing";
+  echo "Please set the default path where gitconvex can maintain its data";
+  echo "========================================="
+  echo "export GITCONVEX_DEFAULT_PATH=/some/path"
+  echo "========================================="
+  exit 1;
+fi
+
+echo "🚀 Building server modules"
+go generate
+go build -v -o ./dist
\ No newline at end of file
diff --git a/build_scripts/build_ui.sh b/build_scripts/build_ui.sh
new file mode 100755
index 0000000..d57eeda
--- /dev/null
+++ b/build_scripts/build_ui.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+echo "⏬ Cloning gitconvex react repo"
+git clone https://github.com/neel1996/gitconvex-ui.git ui/
+cd ui
+
+echo "⏳ Installing UI dependencies..."
+npm install
+export NODE_ENV=production
+npm i -g create-react-app tailwindcss@1.6.0
+npm run build:tailwind
+
+echo "🔧 Building react UI bundle"
+npm run build
+mv ./build ../build
+cd ..
\ No newline at end of file
diff --git a/git/branch/git_branch_add.go b/git/branch/git_branch_add.go
index fea195d..ab0f839 100644
--- a/git/branch/git_branch_add.go
+++ b/git/branch/git_branch_add.go
@@ -11,16 +11,16 @@ type Add interface {
 }
 
 type addBranch struct {
-	Repo         *git2go.Repository
-	BranchName   string
-	RemoteSwitch bool
-	TargetCommit *git2go.Commit
+	repo         *git2go.Repository
+	branchName   string
+	remoteSwitch bool
+	targetCommit *git2go.Commit
 }
 
 func (a addBranch) AddBranch() string {
-	targetCommit := a.TargetCommit
-	repo := a.Repo
-	branchName := a.BranchName
+	targetCommit := a.targetCommit
+	repo := a.repo
+	branchName := a.branchName
 	head, headErr := repo.Head()
 
 	logger.Log(fmt.Sprintf("Adding new branch -> %s", branchName), global.StatusInfo)
@@ -59,9 +59,9 @@ func (a addBranch) validateTargetCommit(targetCommit *git2go.Commit, repo *git2g
 
 func NewAddBranch(repo *git2go.Repository, branchName string, remoteSwitch bool, targetCommit *git2go.Commit) Add {
 	return addBranch{
-		Repo:         repo,
-		BranchName:   branchName,
-		RemoteSwitch: remoteSwitch,
-		TargetCommit: targetCommit,
+		repo:         repo,
+		branchName:   branchName,
+		remoteSwitch: remoteSwitch,
+		targetCommit: targetCommit,
 	}
 }
diff --git a/git/branch/git_branch_checkout.go b/git/branch/git_branch_checkout.go
index b8fcdec..e958d08 100644
--- a/git/branch/git_branch_checkout.go
+++ b/git/branch/git_branch_checkout.go
@@ -13,8 +13,8 @@ type Checkout interface {
 }
 
 type branchCheckout struct {
-	Repo       *git2go.Repository
-	BranchName string
+	repo       *git2go.Repository
+	branchName string
 }
 
 type validatedBranchDetails struct {
@@ -41,7 +41,7 @@ func checkErrorAndPanic(err error) bool {
 // CheckoutBranch checks out the branchName received as argument
 func (b branchCheckout) CheckoutBranch() string {
 	var errStatus bool
-	branchName := b.BranchName
+	branchName := b.branchName
 
 	defer func() string {
 		if r := recover(); r != nil {
@@ -69,8 +69,8 @@ func (b branchCheckout) CheckoutBranch() string {
 
 func (b branchCheckout) checkoutRemoteBranch(branchDetails validatedBranchDetails) bool {
 	var errStatus bool
-	branchName := b.BranchName
-	repo := b.Repo
+	branchName := b.branchName
+	repo := b.repo
 
 	logger.Log(fmt.Sprintf("Branch - %s is a remote branch. Trying with intermediate remote fetch!", branchName), global.StatusWarning)
 
@@ -107,8 +107,8 @@ func (b branchCheckout) checkoutRemoteBranch(branchDetails validatedBranchDetail
 
 func (b branchCheckout) checkoutLocalBranch(branchDetails validatedBranchDetails) bool {
 	errStatus := false
-	repo := b.Repo
-	branchName := b.BranchName
+	repo := b.repo
+	branchName := b.branchName
 
 	branch, branchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
 	errStatus = checkErrorAndPanic(branchErr)
@@ -188,7 +188,7 @@ func splitAndReturnBranchName(delimiter string, branchName string) string {
 
 func NewBranchCheckout(repo *git2go.Repository, branchName string) Checkout {
 	return branchCheckout{
-		Repo:       repo,
-		BranchName: branchName,
+		repo:       repo,
+		branchName: branchName,
 	}
 }
diff --git a/git/branch/git_branch_compare.go b/git/branch/git_branch_compare.go
index cee88fe..bea693e 100644
--- a/git/branch/git_branch_compare.go
+++ b/git/branch/git_branch_compare.go
@@ -13,9 +13,9 @@ type Compare interface {
 }
 
 type branchCompare struct {
-	Repo       *git2go.Repository
-	BaseBranch string
-	DiffBranch string
+	repo       *git2go.Repository
+	baseBranch string
+	diffBranch string
 }
 
 func returnBranchCompareError(errString string) []*model.BranchCompareResults {
@@ -31,10 +31,10 @@ func returnBranchCompareError(errString string) []*model.BranchCompareResults {
 func (b branchCompare) CompareBranch() []*model.BranchCompareResults {
 	var diffCommits []*model.BranchCompareResults
 	var filteredCommits []model.GitCommits
-	repo := b.Repo
+	repo := b.repo
 
-	baseBranch, baseBranchErr := repo.LookupBranch(b.BaseBranch, git2go.BranchLocal)
-	compareBranch, compareBranchErr := repo.LookupBranch(b.DiffBranch, git2go.BranchLocal)
+	baseBranch, baseBranchErr := repo.LookupBranch(b.baseBranch, git2go.BranchLocal)
+	compareBranch, compareBranchErr := repo.LookupBranch(b.diffBranch, git2go.BranchLocal)
 
 	if baseBranchErr != nil || compareBranchErr != nil {
 		return returnBranchCompareError("Unable to lookup target branches from the repo")
@@ -168,8 +168,8 @@ func sortCommitsBasedOnDate(commitMap map[string][]*model.GitCommits, diffCommit
 
 func NewBranchCompare(repo *git2go.Repository, baseBranch string, diffBranch string) Compare {
 	return branchCompare{
-		Repo:       repo,
-		BaseBranch: baseBranch,
-		DiffBranch: diffBranch,
+		repo:       repo,
+		baseBranch: baseBranch,
+		diffBranch: diffBranch,
 	}
 }
diff --git a/git/branch/git_branch_delete.go b/git/branch/git_branch_delete.go
index a5969ff..59c977a 100644
--- a/git/branch/git_branch_delete.go
+++ b/git/branch/git_branch_delete.go
@@ -12,14 +12,14 @@ type Delete interface {
 }
 
 type deleteBranch struct {
-	Repo       *git2go.Repository
-	BranchName string
+	repo       *git2go.Repository
+	branchName string
 }
 
 // DeleteBranch deletes a branch from the repo
 func (inputs deleteBranch) DeleteBranch() *model.BranchDeleteStatus {
-	repo := inputs.Repo
-	branchName := inputs.BranchName
+	repo := inputs.repo
+	branchName := inputs.branchName
 	branch, deleteBranchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
 
 	if deleteBranchErr != nil {
@@ -41,7 +41,7 @@ func (inputs deleteBranch) DeleteBranch() *model.BranchDeleteStatus {
 
 func NewDeleteBranch(repo *git2go.Repository, branchName string) Delete {
 	return deleteBranch{
-		Repo:       repo,
-		BranchName: branchName,
+		repo:       repo,
+		branchName: branchName,
 	}
 }
diff --git a/git/branch/git_branch_list.go b/git/branch/git_branch_list.go
index 037e226..df3bdcf 100644
--- a/git/branch/git_branch_list.go
+++ b/git/branch/git_branch_list.go
@@ -13,7 +13,7 @@ type List interface {
 }
 
 type listBranch struct {
-	Repo            *git2go.Repository
+	repo            *git2go.Repository
 	localBranchList []*string
 	allBranchList   []*string
 }
@@ -28,7 +28,7 @@ type ListOfBranches struct {
 // The result will be returned as a struct with the current branch and all the available branches
 func (l listBranch) ListBranches(branchChan chan ListOfBranches) {
 	var currentBranch string
-	repo := l.Repo
+	repo := l.repo
 
 	defer close(branchChan)
 
@@ -105,6 +105,6 @@ func getCurrentBranchName(head *git2go.Reference) string {
 
 func NewBranchListInterface(repo *git2go.Repository) List {
 	return listBranch{
-		Repo: repo,
+		repo: repo,
 	}
 }

From 972b23aaa9d0dbb17dae3dbd2fba70c420ffec03 Mon Sep 17 00:00:00 2001
From: Neel <47709856+neel1996@users.noreply.github.com>
Date: Sat, 19 Jun 2021 15:15:50 +0530
Subject: [PATCH 011/148] update codeql to be compatible with Makefile target

---
 .github/workflows/codeql-analysis.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index bfe85c0..973d455 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -79,6 +79,7 @@ jobs:
       #    uses a compiled language
 
       - run: |
+          export GITCONVEX_DEFAULT_PATH=$(pwd)
           make build-server
 
       - name: Perform CodeQL Analysis

From 8da07df33adb3e680193ea3f6d330662e67e907a Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 20 Jun 2021 23:02:30 +0530
Subject: [PATCH 012/148] update test repo setup for running the test suite

---
 .github/workflows/go-collab.yml               |  2 +-
 .github/workflows/go.yml                      |  2 +-
 ...ne_test.go => beforeAll_git_setup_test.go} | 50 +++++++++++++++++--
 tests/git_commit_compare_test.go              |  2 +-
 tests/git_commit_files_test.go                |  2 +-
 tests/git_unpushed_commits_test.go            | 10 ++--
 tests/update_repo_name_test.go                | 41 ---------------
 7 files changed, 55 insertions(+), 54 deletions(-)
 rename tests/{beforeAll_git_clone_test.go => beforeAll_git_setup_test.go} (58%)
 delete mode 100644 tests/update_repo_name_test.go

diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index f19e825..6973867 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -19,7 +19,7 @@ jobs:
     runs-on: ubuntu-latest
     env:
       PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
-      GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/starfleet
+      GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/gitconvex-test
       GITCONVEX_DEFAULT_PATH: /usr/local/gitconvex
 
     steps:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index ab365e3..6bbf0cd 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -19,7 +19,7 @@ jobs:
     runs-on: ubuntu-latest
     env:
       PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
-      GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/starfleet
+      GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/gitconvex-test
       GITCONVEX_DEFAULT_PATH: /usr/local/gitconvex
 
     steps:
diff --git a/tests/beforeAll_git_clone_test.go b/tests/beforeAll_git_setup_test.go
similarity index 58%
rename from tests/beforeAll_git_clone_test.go
rename to tests/beforeAll_git_setup_test.go
index 90ccd6c..3aad18d 100644
--- a/tests/beforeAll_git_clone_test.go
+++ b/tests/beforeAll_git_setup_test.go
@@ -1,6 +1,7 @@
 package tests
 
 import (
+	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git"
 	"github.com/sirupsen/logrus"
 	"os"
@@ -23,16 +24,15 @@ func TestMain(m *testing.M) {
 	testObject = git.CloneStruct{
 		RepoName:   "",
 		RepoPath:   TestRepo,
-		RepoURL:    "https://github.com/neel1996/starfleet.git",
+		RepoURL:    "https://github.com/neel1996/gitconvex-test.git",
 		AuthOption: "noauth",
 		SSHKeyPath: "",
 		UserName:   "",
 		Password:   "",
 	}
-	_, err := testObject.CloneRepo()
-	if err != nil {
-		logger.Error("Unable to clone the test repo")
-		os.Exit(2)
+
+	if testRepoSetup(testObject) {
+		return
 	}
 
 	logger.Info("Initiating integration tests")
@@ -40,6 +40,46 @@ func TestMain(m *testing.M) {
 	tearDownTests()
 }
 
+func testRepoSetup(testObject git.CloneInterface) bool {
+	cloneTestRepo(testObject)
+
+	if stageAndCommit() {
+		return true
+	}
+
+	return false
+}
+
+func stageAndCommit() bool {
+	repository, repoErr := git2go.OpenRepository(TestRepo)
+	if repoErr != nil {
+		return true
+	}
+
+	git.StageAllStruct{Repo: repository}.StageAllItems()
+	git.CommitStruct{
+		Repo:          repository,
+		CommitMessage: "Initial commit",
+		RepoPath:      TestRepo,
+	}.CommitChanges()
+
+	git.AddRemoteStruct{
+		Repo:       repository,
+		RemoteName: "origin",
+		RemoteURL:  "https://github.com/neel1996/gitconvex-test.git",
+	}.AddRemote()
+
+	return false
+}
+
+func cloneTestRepo(testObject git.CloneInterface) {
+	_, err := testObject.CloneRepo()
+	if err != nil {
+		logger.Error("Unable to clone the test repo")
+		os.Exit(2)
+	}
+}
+
 func tearDownTests() {
 	removeFlag, _ := strconv.ParseBool(os.Getenv("GITCONVEX_DELETE_TEST_REPO"))
 	if !removeFlag {
diff --git a/tests/git_commit_compare_test.go b/tests/git_commit_compare_test.go
index 648b6ec..f5162bb 100644
--- a/tests/git_commit_compare_test.go
+++ b/tests/git_commit_compare_test.go
@@ -28,7 +28,7 @@ func TestCompareCommit(t *testing.T) {
 			repo                *git.Repository
 			baseCommitString    string
 			compareCommitString string
-		}{repo: r, baseCommitString: *sampleCommits.Commits[1].Hash, compareCommitString: *sampleCommits.Commits[2].Hash}},
+		}{repo: r, baseCommitString: *sampleCommits.Commits[0].Hash, compareCommitString: *sampleCommits.Commits[1].Hash}},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/tests/git_commit_files_test.go b/tests/git_commit_files_test.go
index ea22e0a..9baddfa 100644
--- a/tests/git_commit_files_test.go
+++ b/tests/git_commit_files_test.go
@@ -26,7 +26,7 @@ func TestCommitFileList(t *testing.T) {
 		{name: "Git commit file list test case", args: struct {
 			repo       *git.Repository
 			commitHash string
-		}{repo: r, commitHash: *sampleCommits.Commits[1].Hash}},
+		}{repo: r, commitHash: *sampleCommits.Commits[0].Hash}},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/tests/git_unpushed_commits_test.go b/tests/git_unpushed_commits_test.go
index a756995..53fab02 100644
--- a/tests/git_unpushed_commits_test.go
+++ b/tests/git_unpushed_commits_test.go
@@ -3,8 +3,8 @@ package tests
 import (
 	"github.com/libgit2/git2go/v31"
 	git2 "github.com/neel1996/gitconvex/git"
+	"github.com/stretchr/testify/assert"
 	"io/ioutil"
-	"strings"
 	"testing"
 )
 
@@ -53,9 +53,11 @@ func TestUnPushedCommits(t *testing.T) {
 				Repo:      tt.args.repo,
 				RemoteRef: tt.args.remoteRef,
 			}
-			if got := testObj.UnPushedCommits(); !strings.Contains(*got.GitCommits[0].CommitMessage, "Test Commit") {
-				t.Errorf("UnPushedCommits() = %v, want %v", got, tt.want)
-			}
+
+			got := testObj.UnPushedCommits()
+
+			assert.NotNil(t, got)
+			assert.NotEmpty(t, *got.GitCommits[0].CommitMessage)
 		})
 	}
 }
diff --git a/tests/update_repo_name_test.go b/tests/update_repo_name_test.go
deleted file mode 100644
index 9beb6a9..0000000
--- a/tests/update_repo_name_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package tests
-
-import (
-	"github.com/neel1996/gitconvex/api"
-	"github.com/neel1996/gitconvex/utils"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestUpdateRepoName(t *testing.T) {
-	var testObj api.AddRepoInterface
-	testObj = api.AddRepoInputs{
-		RepoName: "test", RepoPath: "..", CloneSwitch: false, RepoURL: "", InitSwitch: false, AuthOption: "", UserName: "", Password: "",
-	}
-	_ = utils.EnvConfigFileGenerator()
-	testRepoId := testObj.AddRepo().RepoID
-
-	type args struct {
-		repoId   string
-		repoName string
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    string
-		wantErr bool
-	}{
-		{name: "test script for rename repo API", args: struct {
-			repoId   string
-			repoName string
-		}{repoId: testRepoId, repoName: "NewTest"}, want: "Repo name updated successfully", wantErr: false},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got, err := api.UpdateRepoName(tt.args.repoId, tt.args.repoName)
-
-			assert.Nil(t, err)
-			assert.Equal(t, tt.want, got)
-		})
-	}
-}

From 737de58214aa26574d2f7d3f4dc677c8c2ea9e4a Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 20 Jun 2021 23:24:49 +0530
Subject: [PATCH 013/148] add new test for branch compare

---
 tests/beforeAll_git_setup_test.go             | 28 ++++---------
 tests/git_branch_compare_test.go              | 42 +++++++++++++++++++
 ...branch_test.go => git_branch_list_test.go} |  0
 3 files changed, 49 insertions(+), 21 deletions(-)
 create mode 100644 tests/git_branch_compare_test.go
 rename tests/{git_branch_test.go => git_branch_list_test.go} (100%)

diff --git a/tests/beforeAll_git_setup_test.go b/tests/beforeAll_git_setup_test.go
index 3aad18d..32d2357 100644
--- a/tests/beforeAll_git_setup_test.go
+++ b/tests/beforeAll_git_setup_test.go
@@ -4,6 +4,7 @@ import (
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git"
 	"github.com/sirupsen/logrus"
+	"io/ioutil"
 	"os"
 	"strconv"
 	"testing"
@@ -31,44 +32,29 @@ func TestMain(m *testing.M) {
 		Password:   "",
 	}
 
-	if testRepoSetup(testObject) {
-		return
-	}
+	cloneTestRepo(testObject)
 
 	logger.Info("Initiating integration tests")
 	m.Run()
 	tearDownTests()
 }
 
-func testRepoSetup(testObject git.CloneInterface) bool {
-	cloneTestRepo(testObject)
-
-	if stageAndCommit() {
-		return true
-	}
-
-	return false
-}
-
-func stageAndCommit() bool {
+func SetupTestRepoStageAndCommit(msg string) bool {
 	repository, repoErr := git2go.OpenRepository(TestRepo)
 	if repoErr != nil {
 		return true
 	}
 
+	initFile := "init_file.txt"
+	_ = ioutil.WriteFile(TestRepo+"/"+initFile, []byte{byte(63)}, 0755)
+
 	git.StageAllStruct{Repo: repository}.StageAllItems()
 	git.CommitStruct{
 		Repo:          repository,
-		CommitMessage: "Initial commit",
+		CommitMessage: msg,
 		RepoPath:      TestRepo,
 	}.CommitChanges()
 
-	git.AddRemoteStruct{
-		Repo:       repository,
-		RemoteName: "origin",
-		RemoteURL:  "https://github.com/neel1996/gitconvex-test.git",
-	}.AddRemote()
-
 	return false
 }
 
diff --git a/tests/git_branch_compare_test.go b/tests/git_branch_compare_test.go
new file mode 100644
index 0000000..ba65356
--- /dev/null
+++ b/tests/git_branch_compare_test.go
@@ -0,0 +1,42 @@
+package tests
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func Test_branchCompare_CompareBranch(t *testing.T) {
+	r, _ := git2go.OpenRepository(TestRepo)
+
+	type fields struct {
+		repo       *git2go.Repository
+		baseBranch string
+		diffBranch string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+	}{
+		{name: "Branch compare test", fields: struct {
+			repo       *git2go.Repository
+			baseBranch string
+			diffBranch string
+		}{repo: r, baseBranch: "master", diffBranch: "test_compare"}},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			branch.NewAddBranch(r, tt.fields.diffBranch, false, nil).AddBranch()
+			branch.NewBranchCheckout(r, tt.fields.diffBranch).CheckoutBranch()
+			SetupTestRepoStageAndCommit("Comparison commit for branch compare")
+
+			branch.NewBranchCheckout(r, tt.fields.baseBranch).CheckoutBranch()
+
+			b := branch.NewBranchCompare(r, tt.fields.baseBranch, tt.fields.diffBranch)
+			got := b.CompareBranch()
+
+			assert.NotEmpty(t, got)
+		})
+	}
+}
diff --git a/tests/git_branch_test.go b/tests/git_branch_list_test.go
similarity index 100%
rename from tests/git_branch_test.go
rename to tests/git_branch_list_test.go

From 54c7cabf9293796bcf38cf1fc2cddae6944a8e00 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 21 Jun 2021 22:23:36 +0530
Subject: [PATCH 014/148] add remote deletion interface to the common remote
 package

---
 git/git_remote_add.go           | 35 -----------------------
 git/git_remote_delete.go        | 44 -----------------------------
 git/remote/git_remote_add.go    | 43 +++++++++++++++++++++++++++++
 git/remote/git_remote_delete.go | 49 +++++++++++++++++++++++++++++++++
 git/remote/remote.go            | 39 ++++++++++++++++++++++++++
 graph/schema.resolvers.go       | 22 +++++++--------
 tests/git_remote_add_test.go    | 20 ++++----------
 tests/git_remote_delete_test.go | 18 ++++--------
 8 files changed, 152 insertions(+), 118 deletions(-)
 delete mode 100644 git/git_remote_add.go
 delete mode 100644 git/git_remote_delete.go
 create mode 100644 git/remote/git_remote_add.go
 create mode 100644 git/remote/git_remote_delete.go
 create mode 100644 git/remote/remote.go

diff --git a/git/git_remote_add.go b/git/git_remote_add.go
deleted file mode 100644
index b3b3b84..0000000
--- a/git/git_remote_add.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-)
-
-type AddRemoteInterface interface {
-	AddRemote() *model.RemoteMutationResult
-}
-
-type AddRemoteStruct struct {
-	Repo       *git2go.Repository
-	RemoteName string
-	RemoteURL  string
-}
-
-// AddRemote adds a new remote to the target git repo
-func (a AddRemoteStruct) AddRemote() *model.RemoteMutationResult {
-	repo := a.Repo
-	remoteName := a.RemoteName
-	remoteURL := a.RemoteURL
-
-	remote, err := repo.Remotes.Create(remoteName, remoteURL)
-
-	if err == nil {
-		logger.Log(fmt.Sprintf("New remote %s added to the repo", remote.Name()), global.StatusInfo)
-		return &model.RemoteMutationResult{Status: global.RemoteAddSuccess}
-	} else {
-		logger.Log("Remote addition Failed -> "+err.Error(), global.StatusError)
-		return &model.RemoteMutationResult{Status: global.RemoteAddError}
-	}
-}
diff --git a/git/git_remote_delete.go b/git/git_remote_delete.go
deleted file mode 100644
index f3768bf..0000000
--- a/git/git_remote_delete.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-)
-
-type DeleteRemoteInterface interface {
-	DeleteRemote() *model.RemoteMutationResult
-}
-
-type DeleteRemoteStruct struct {
-	Repo       *git2go.Repository
-	RemoteName string
-}
-
-func (d *DeleteRemoteStruct) DeleteRemote() *model.RemoteMutationResult {
-	repo := d.Repo
-	remoteToBeDeleted := d.RemoteName
-
-	remoteList, listErr := repo.Remotes.List()
-	if listErr != nil {
-		logger.Log(listErr.Error(), global.StatusError)
-		return &model.RemoteMutationResult{Status: global.RemoteDeleteError}
-	}
-
-	for _, remoteEntry := range remoteList {
-		if remoteEntry == remoteToBeDeleted {
-			err := repo.Remotes.Delete(remoteEntry)
-			if err != nil {
-				logger.Log(err.Error(), global.StatusError)
-				return &model.RemoteMutationResult{Status: global.RemoteDeleteError}
-			} else {
-				logger.Log(fmt.Sprintf("The remote => %s deleted from repo", remoteToBeDeleted), global.StatusInfo)
-				return &model.RemoteMutationResult{Status: global.RemoteDeleteSuccess}
-			}
-		}
-	}
-
-	logger.Log(fmt.Sprintf("Remote => %s cannot be found in the repo", remoteToBeDeleted), global.StatusError)
-	return &model.RemoteMutationResult{Status: global.RemoteDeleteError}
-}
diff --git a/git/remote/git_remote_add.go b/git/remote/git_remote_add.go
new file mode 100644
index 0000000..d1a0bf1
--- /dev/null
+++ b/git/remote/git_remote_add.go
@@ -0,0 +1,43 @@
+package remote
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type Add interface {
+	NewRemote() *model.RemoteMutationResult
+}
+
+type addRemote struct {
+	repo       *git2go.Repository
+	remoteName string
+	remoteURL  string
+}
+
+// NewRemote adds a new remote to the target git repo
+func (a addRemote) NewRemote() *model.RemoteMutationResult {
+	repo := a.repo
+	remoteName := a.remoteName
+	remoteURL := a.remoteURL
+
+	remote, err := repo.Remotes.Create(remoteName, remoteURL)
+
+	if err != nil {
+		logger.Log("Remote addition Failed -> "+err.Error(), global.StatusError)
+		return &model.RemoteMutationResult{Status: global.RemoteAddError}
+	}
+
+	logger.Log(fmt.Sprintf("New remote %s added to the repo", remote.Name()), global.StatusInfo)
+	return &model.RemoteMutationResult{Status: global.RemoteAddSuccess}
+}
+
+func NewAddRemote(repo *git2go.Repository, remoteName string, remoteURL string) Add {
+	return addRemote{
+		repo:       repo,
+		remoteName: remoteName,
+		remoteURL:  remoteURL,
+	}
+}
diff --git a/git/remote/git_remote_delete.go b/git/remote/git_remote_delete.go
new file mode 100644
index 0000000..2f07eca
--- /dev/null
+++ b/git/remote/git_remote_delete.go
@@ -0,0 +1,49 @@
+package remote
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type Delete interface {
+	DeleteRemote() *model.RemoteMutationResult
+}
+
+type deleteRemote struct {
+	repo       *git2go.Repository
+	remoteName string
+}
+
+func (d deleteRemote) DeleteRemote() *model.RemoteMutationResult {
+	remoteToBeDeleted := d.remoteName
+
+	deletionError := &model.RemoteMutationResult{Status: global.RemoteDeleteError}
+
+	err := d.deleteSelectedRemote(d.remoteName)
+	if err != nil {
+		logger.Log(fmt.Sprintf("Remote => %s cannot be found in the repo", remoteToBeDeleted), global.StatusError)
+		return deletionError
+	}
+
+	return &model.RemoteMutationResult{Status: global.RemoteDeleteSuccess}
+}
+
+func (d *deleteRemote) deleteSelectedRemote(remoteEntry string) error {
+	err := d.repo.Remotes.Delete(remoteEntry)
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return err
+	}
+
+	logger.Log(fmt.Sprintf("The remote => %s deleted from repo", d.remoteName), global.StatusInfo)
+	return nil
+}
+
+func NewDeleteRemoteInterface(repo *git2go.Repository, remoteName string) Delete {
+	return deleteRemote{
+		repo:       repo,
+		remoteName: remoteName,
+	}
+}
diff --git a/git/remote/remote.go b/git/remote/remote.go
new file mode 100644
index 0000000..c71e06b
--- /dev/null
+++ b/git/remote/remote.go
@@ -0,0 +1,39 @@
+package remote
+
+import (
+	"errors"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+var logger global.Logger
+
+type Remote interface {
+	GitAddRemote() (*model.RemoteMutationResult, error)
+	GitDeleteRemote() (*model.RemoteMutationResult, error)
+}
+
+type Operation struct {
+	Add    Add
+	Delete Delete
+}
+
+func (r Operation) GitAddRemote() (*model.RemoteMutationResult, error) {
+	addRemoteResult := r.Add.NewRemote()
+
+	if addRemoteResult.Status == global.RemoteAddError {
+		return nil, errors.New(global.RemoteAddError)
+	}
+
+	return addRemoteResult, nil
+}
+
+func (r Operation) GitDeleteRemote() (*model.RemoteMutationResult, error) {
+	deleteRemoteResult := r.Delete.DeleteRemote()
+
+	if deleteRemoteResult.Status == global.RemoteDeleteError {
+		return nil, errors.New(global.RemoteDeleteError)
+	}
+
+	return deleteRemoteResult, nil
+}
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index 562a816..8ebfa3d 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -6,6 +6,7 @@ package graph
 import (
 	"context"
 	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/remote"
 
 	"github.com/neel1996/gitconvex/api"
 	"github.com/neel1996/gitconvex/git"
@@ -333,13 +334,10 @@ func (r *mutationResolver) AddRemote(ctx context.Context, repoID string, remoteN
 		return &model.RemoteMutationResult{Status: global.RemoteAddError}, nil
 	}
 
-	var addRemoteObject git.AddRemoteInterface
-	addRemoteObject = git.AddRemoteStruct{
-		Repo:       repo.GitRepo,
-		RemoteName: remoteName,
-		RemoteURL:  remoteURL,
-	}
-	return addRemoteObject.AddRemote(), nil
+	addRemote := remote.NewAddRemote(repo.GitRepo, remoteName, remoteURL)
+	remoteObject := remote.Operation{Add: addRemote}
+
+	return remoteObject.GitAddRemote()
 }
 
 func (r *mutationResolver) DeleteRemote(ctx context.Context, repoID string, remoteName string) (*model.RemoteMutationResult, error) {
@@ -355,12 +353,12 @@ func (r *mutationResolver) DeleteRemote(ctx context.Context, repoID string, remo
 		return &model.RemoteMutationResult{Status: global.RemoteAddError}, nil
 	}
 
-	var addRemoteObject git.DeleteRemoteInterface
-	addRemoteObject = &git.DeleteRemoteStruct{
-		Repo:       repo.GitRepo,
-		RemoteName: remoteName,
+	deleteRemote := remote.NewDeleteRemoteInterface(repo.GitRepo, remoteName)
+	remoteObject := remote.Operation{
+		Delete: deleteRemote,
 	}
-	return addRemoteObject.DeleteRemote(), nil
+
+	return remoteObject.GitDeleteRemote()
 }
 
 func (r *mutationResolver) EditRemote(ctx context.Context, repoID string, remoteName string, remoteURL string) (*model.RemoteMutationResult, error) {
diff --git a/tests/git_remote_add_test.go b/tests/git_remote_add_test.go
index 8b9a37f..5cf2454 100644
--- a/tests/git_remote_add_test.go
+++ b/tests/git_remote_add_test.go
@@ -2,7 +2,7 @@ package tests
 
 import (
 	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/remote"
 	"github.com/stretchr/testify/assert"
 	"testing"
 )
@@ -28,21 +28,13 @@ func TestAddRemote(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.AddRemoteInterface
-			testObj = git2.AddRemoteStruct{
-				Repo:       tt.args.repo,
-				RemoteName: tt.args.remoteName,
-				RemoteURL:  tt.args.remoteURL,
-			}
-			got := testObj.AddRemote()
+			var testObj remote.Add
 
-			assert.Equal(t, tt.want, got.Status)
+			testObj = remote.NewAddRemote(r, tt.args.remoteName, tt.args.remoteURL)
+			got := testObj.NewRemote()
 
-			obj := git2.DeleteRemoteStruct{
-				Repo:       r,
-				RemoteName: tt.args.remoteName,
-			}
-			obj.DeleteRemote()
+			assert.Equal(t, tt.want, got.Status)
+			remote.NewDeleteRemoteInterface(r, tt.args.remoteName).DeleteRemote()
 		})
 	}
 }
diff --git a/tests/git_remote_delete_test.go b/tests/git_remote_delete_test.go
index c0228cc..d355a47 100644
--- a/tests/git_remote_delete_test.go
+++ b/tests/git_remote_delete_test.go
@@ -2,7 +2,7 @@ package tests
 
 import (
 	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/remote"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/stretchr/testify/assert"
@@ -13,13 +13,8 @@ func TestDeleteRemoteStruct_DeleteRemote(t *testing.T) {
 	r, _ := git.OpenRepository(TestRepo)
 
 	testRemoteName := "test_remote"
-	var testObj git2.AddRemoteInterface
-	testObj = git2.AddRemoteStruct{
-		Repo:       r,
-		RemoteName: testRemoteName,
-		RemoteURL:  "git@github.com:neel1996/gitconvex-server.git",
-	}
-	_ = testObj.AddRemote()
+	addRemote := remote.NewAddRemote(r, testRemoteName, "git@github.com:neel1996/gitconvex-server.git")
+	_ = addRemote.NewRemote()
 
 	type fields struct {
 		Repo       git.Repository
@@ -37,11 +32,8 @@ func TestDeleteRemoteStruct_DeleteRemote(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			d := &git2.DeleteRemoteStruct{
-				Repo:       &tt.fields.Repo,
-				RemoteName: tt.fields.RemoteName,
-			}
-			got := d.DeleteRemote()
+			remoteObj := remote.NewDeleteRemoteInterface(&tt.fields.Repo, tt.fields.RemoteName)
+			got := remoteObj.DeleteRemote()
 
 			assert.Equal(t, tt.want.Status, got.Status)
 		})

From 721464d7b306bd31b665b4d56fd85bca7805691c Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 22 Jun 2021 23:59:37 +0530
Subject: [PATCH 015/148] revise repo validator function with interface

---
 api/add_repo.go          |  3 ++-
 git/git_repo_validate.go | 45 ++++++++++++++++++++++++++++++++++------
 2 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/api/add_repo.go b/api/add_repo.go
index bbb5701..d1f7cb7 100644
--- a/api/add_repo.go
+++ b/api/add_repo.go
@@ -164,6 +164,7 @@ func (inputs AddRepoInputs) AddRepo() *model.AddRepoParams {
 	userName := inputs.UserName
 	password := inputs.Password
 	sshKeyPath := inputs.SSHKeyPath
+	repoValidator := git.NewRepoValidator(repoPath, nil)
 
 	if cloneSwitch && len(repoURL) > 0 {
 		currentOs := HealthCheckApi().Os
@@ -208,7 +209,7 @@ func (inputs AddRepoInputs) AddRepo() *model.AddRepoParams {
 		}
 	}
 
-	_, invalidRepoErr := git.RepoValidator(repoPath)
+	invalidRepoErr := repoValidator.ValidateRepoWithPath()
 
 	if invalidRepoErr != nil && !initSwitch {
 		logger.Log(fmt.Sprintf("The repo is not a valid git repo\n%v", invalidRepoErr), global.StatusError)
diff --git a/git/git_repo_validate.go b/git/git_repo_validate.go
index 6d5e3e0..ca4a00f 100644
--- a/git/git_repo_validate.go
+++ b/git/git_repo_validate.go
@@ -1,23 +1,35 @@
 package git
 
 import (
+	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
-	"go/types"
 	"os"
 )
 
-// RepoValidator validates if the specified repoPath represents a valid git repo
-func RepoValidator(repoPath string) (string, error) {
+type RepoValidator interface {
+	ValidateRepoWithPath() error
+	ValidateGitRepository()
+}
+
+type repoValidator struct {
+	repoPath string
+	repo     *git2go.Repository
+}
+
+// ValidateRepoWithPath validates if the specified repoPath represents a valid git repo
+func (r repoValidator) ValidateRepoWithPath() error {
+	repoPath := r.repoPath
+
 	_, err := os.Open(fmt.Sprintf("%v/.git/", repoPath))
 	if err != nil {
-		return "", types.Error{Msg: "The selected folder is not a git repo"}
+		return errors.New("the selected folder is not a git repo")
 	}
 
 	repo, repoErr := git2go.OpenRepository(repoPath)
 	if repoErr != nil {
-		return "", types.Error{Msg: "The selected folder is not a valid git repo"}
+		return errors.New("the selected folder is not a valid git repo")
 	}
 
 	_, headErr := repo.Head()
@@ -25,5 +37,26 @@ func RepoValidator(repoPath string) (string, error) {
 		logger.Log(fmt.Sprintf("Mind that the repo has no HEAD and a fresh commit is required -> %s", headErr.Error()), global.StatusWarning)
 	}
 
-	return "Repo is valid!", nil
+	return nil
+}
+
+func (r repoValidator) ValidateGitRepository() {
+	repo := r.repo
+
+	defer func() {
+		if panicValue := recover(); panicValue != nil {
+			logger.Log(fmt.Sprintf("%v", panicValue), global.StatusError)
+		}
+	}()
+
+	if repo == nil {
+		panic(errors.New("repository is nil and cannot be used for performing the desired operation"))
+	}
+}
+
+func NewRepoValidator(repoPath string, repo *git2go.Repository) RepoValidator {
+	return repoValidator{
+		repoPath: repoPath,
+		repo:     repo,
+	}
 }

From 8372317d44b7be283834787aaeabb306700d5054 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 23 Jun 2021 22:55:25 +0530
Subject: [PATCH 016/148] remove test repo removal from before all test

---
 git/remote/git_remote_list.go      |  1 +
 git/remote/git_remote_list_test.go |  1 +
 tests/beforeAll_git_setup_test.go  | 12 +++++++-----
 3 files changed, 9 insertions(+), 5 deletions(-)
 create mode 100644 git/remote/git_remote_list.go
 create mode 100644 git/remote/git_remote_list_test.go

diff --git a/git/remote/git_remote_list.go b/git/remote/git_remote_list.go
new file mode 100644
index 0000000..fbe5b64
--- /dev/null
+++ b/git/remote/git_remote_list.go
@@ -0,0 +1 @@
+package remote
diff --git a/git/remote/git_remote_list_test.go b/git/remote/git_remote_list_test.go
new file mode 100644
index 0000000..fbe5b64
--- /dev/null
+++ b/git/remote/git_remote_list_test.go
@@ -0,0 +1 @@
+package remote
diff --git a/tests/beforeAll_git_setup_test.go b/tests/beforeAll_git_setup_test.go
index 32d2357..848f45b 100644
--- a/tests/beforeAll_git_setup_test.go
+++ b/tests/beforeAll_git_setup_test.go
@@ -73,9 +73,11 @@ func tearDownTests() {
 		return
 	}
 
-	err := os.RemoveAll(os.Getenv("GITCONVEX_TEST_REPO"))
-	if err != nil {
-		logger.Error(err)
-		return
-	}
+	// Enable for deleting the test repo after running the tests
+
+	//err := os.RemoveAll(os.Getenv("GITCONVEX_TEST_REPO"))
+	//if err != nil {
+	//	logger.Error(err)
+	//	return
+	//}
 }

From 2d12c3ed485cbd6a9cef5271802fd11a80c4b4c1 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 24 Jun 2021 23:45:19 +0530
Subject: [PATCH 017/148] revise remote add and delete operations with new test
 suites and validations

---
 git/remote/git_remote_add.go         | 36 ++++++++++++++------
 git/remote/git_remote_add_test.go    | 50 ++++++++++++++++++++++++++++
 git/remote/git_remote_delete.go      | 32 ++++++++++++------
 git/remote/git_remote_delete_test.go | 50 ++++++++++++++++++++++++++++
 tests/git_remote_add_test.go         | 40 ----------------------
 tests/git_remote_delete_test.go      | 41 -----------------------
 6 files changed, 148 insertions(+), 101 deletions(-)
 create mode 100644 git/remote/git_remote_add_test.go
 create mode 100644 git/remote/git_remote_delete_test.go
 delete mode 100644 tests/git_remote_add_test.go
 delete mode 100644 tests/git_remote_delete_test.go

diff --git a/git/remote/git_remote_add.go b/git/remote/git_remote_add.go
index d1a0bf1..0116539 100644
--- a/git/remote/git_remote_add.go
+++ b/git/remote/git_remote_add.go
@@ -1,14 +1,14 @@
 package remote
 
 import (
+	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
 )
 
 type Add interface {
-	NewRemote() *model.RemoteMutationResult
+	NewRemote() error
 }
 
 type addRemote struct {
@@ -18,20 +18,36 @@ type addRemote struct {
 }
 
 // NewRemote adds a new remote to the target git repo
-func (a addRemote) NewRemote() *model.RemoteMutationResult {
-	repo := a.repo
-	remoteName := a.remoteName
-	remoteURL := a.remoteURL
-
-	remote, err := repo.Remotes.Create(remoteName, remoteURL)
+func (a addRemote) NewRemote() error {
+	if validationErr := a.validateRemoteFields(); validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return validationErr
+	}
 
+	remote, err := a.repo.Remotes.Create(a.remoteName, a.remoteURL)
 	if err != nil {
 		logger.Log("Remote addition Failed -> "+err.Error(), global.StatusError)
-		return &model.RemoteMutationResult{Status: global.RemoteAddError}
+		return err
 	}
 
 	logger.Log(fmt.Sprintf("New remote %s added to the repo", remote.Name()), global.StatusInfo)
-	return &model.RemoteMutationResult{Status: global.RemoteAddSuccess}
+	return nil
+}
+
+func (a addRemote) validateRemoteFields() error {
+	if a.repo == nil {
+		return errors.New("repo is nil")
+	}
+
+	if a.remoteName == "" {
+		return errors.New("remote name cannot be empty")
+	}
+
+	if a.remoteURL == "" {
+		return errors.New("remote URL is empty")
+	}
+
+	return nil
 }
 
 func NewAddRemote(repo *git2go.Repository, remoteName string, remoteURL string) Add {
diff --git a/git/remote/git_remote_add_test.go b/git/remote/git_remote_add_test.go
new file mode 100644
index 0000000..6d5ec17
--- /dev/null
+++ b/git/remote/git_remote_add_test.go
@@ -0,0 +1,50 @@
+package remote
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type RemoteAddTestSuite struct {
+	suite.Suite
+	addRemote Add
+}
+
+func TestRemoteAddTestSuite(t *testing.T) {
+	suite.Run(t, new(RemoteAddTestSuite))
+}
+
+func (suite *RemoteAddTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.addRemote = NewAddRemote(r, "new_origin", "https://github.com/neel1996/gitconvex-test.git")
+}
+
+func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenNewRemoteIsAdded_ShouldReturnNoError() {
+	err := suite.addRemote.NewRemote()
+
+	suite.Nil(err)
+}
+
+func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRequiredFieldsAreEmpty_ShouldReturnError() {
+	suite.addRemote = NewAddRemote(nil, "", "")
+
+	err := suite.addRemote.NewRemote()
+
+	suite.NotNil(err)
+}
+
+func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteCreationFails_ShouldReturnError() {
+	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+
+	suite.addRemote = NewAddRemote(r, "new_origin", "https://github.com/neel1996/gitconvex-test.git")
+
+	err := suite.addRemote.NewRemote()
+
+	suite.NotNil(err)
+}
diff --git a/git/remote/git_remote_delete.go b/git/remote/git_remote_delete.go
index 2f07eca..0882a4f 100644
--- a/git/remote/git_remote_delete.go
+++ b/git/remote/git_remote_delete.go
@@ -1,14 +1,14 @@
 package remote
 
 import (
+	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
 )
 
 type Delete interface {
-	DeleteRemote() *model.RemoteMutationResult
+	DeleteRemote() error
 }
 
 type deleteRemote struct {
@@ -16,18 +16,30 @@ type deleteRemote struct {
 	remoteName string
 }
 
-func (d deleteRemote) DeleteRemote() *model.RemoteMutationResult {
-	remoteToBeDeleted := d.remoteName
-
-	deletionError := &model.RemoteMutationResult{Status: global.RemoteDeleteError}
+// DeleteRemote deletes the remote based on the specified remoteName
+func (d deleteRemote) DeleteRemote() error {
+	if validationError := d.validateRemoteFields(); validationError != nil {
+		return validationError
+	}
 
 	err := d.deleteSelectedRemote(d.remoteName)
 	if err != nil {
-		logger.Log(fmt.Sprintf("Remote => %s cannot be found in the repo", remoteToBeDeleted), global.StatusError)
-		return deletionError
+		logger.Log(fmt.Sprintf("Remote => %s cannot be found in the repo", d.remoteName), global.StatusError)
+		return err
+	}
+
+	return nil
+}
+
+func (d deleteRemote) validateRemoteFields() error {
+	if d.repo == nil {
+		return errors.New("repo is nil")
 	}
 
-	return &model.RemoteMutationResult{Status: global.RemoteDeleteSuccess}
+	if d.remoteName == "" {
+		return errors.New("remote name cannot be empty")
+	}
+	return nil
 }
 
 func (d *deleteRemote) deleteSelectedRemote(remoteEntry string) error {
@@ -41,7 +53,7 @@ func (d *deleteRemote) deleteSelectedRemote(remoteEntry string) error {
 	return nil
 }
 
-func NewDeleteRemoteInterface(repo *git2go.Repository, remoteName string) Delete {
+func NewDeleteRemote(repo *git2go.Repository, remoteName string) Delete {
 	return deleteRemote{
 		repo:       repo,
 		remoteName: remoteName,
diff --git a/git/remote/git_remote_delete_test.go b/git/remote/git_remote_delete_test.go
new file mode 100644
index 0000000..7a24790
--- /dev/null
+++ b/git/remote/git_remote_delete_test.go
@@ -0,0 +1,50 @@
+package remote
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type RemoteDeleteTestSuite struct {
+	suite.Suite
+	deleteRemote Delete
+}
+
+func TestRemoteDeleteTestSuite(t *testing.T) {
+	suite.Run(t, new(RemoteDeleteTestSuite))
+}
+
+func (suite *RemoteDeleteTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.deleteRemote = NewDeleteRemote(r, "new_origin")
+}
+
+func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenNewRemoteIsDeleted_ShouldReturnNoError() {
+	err := suite.deleteRemote.DeleteRemote()
+
+	suite.Nil(err)
+}
+
+func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRequiredFieldsAreEmpty_ShouldReturnError() {
+	suite.deleteRemote = NewDeleteRemote(nil, "")
+
+	err := suite.deleteRemote.DeleteRemote()
+
+	suite.NotNil(err)
+}
+
+func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteDeletionFails_ShouldReturnError() {
+	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+
+	suite.deleteRemote = NewDeleteRemote(r, "new_origin")
+
+	err := suite.deleteRemote.DeleteRemote()
+
+	suite.NotNil(err)
+}
diff --git a/tests/git_remote_add_test.go b/tests/git_remote_add_test.go
deleted file mode 100644
index 5cf2454..0000000
--- a/tests/git_remote_add_test.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/git/remote"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestAddRemote(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	type args struct {
-		repo       *git.Repository
-		remoteName string
-		remoteURL  string
-	}
-	tests := []struct {
-		name string
-		args args
-		want string
-	}{
-		{name: "Git remote add test case", args: struct {
-			repo       *git.Repository
-			remoteName string
-			remoteURL  string
-		}{repo: r, remoteName: "test_remote", remoteURL: "https://github.com/neel1996/starfleet.git"}, want: "REMOTE_ADD_SUCCESS"},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObj remote.Add
-
-			testObj = remote.NewAddRemote(r, tt.args.remoteName, tt.args.remoteURL)
-			got := testObj.NewRemote()
-
-			assert.Equal(t, tt.want, got.Status)
-			remote.NewDeleteRemoteInterface(r, tt.args.remoteName).DeleteRemote()
-		})
-	}
-}
diff --git a/tests/git_remote_delete_test.go b/tests/git_remote_delete_test.go
deleted file mode 100644
index d355a47..0000000
--- a/tests/git_remote_delete_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/git/remote"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestDeleteRemoteStruct_DeleteRemote(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	testRemoteName := "test_remote"
-	addRemote := remote.NewAddRemote(r, testRemoteName, "git@github.com:neel1996/gitconvex-server.git")
-	_ = addRemote.NewRemote()
-
-	type fields struct {
-		Repo       git.Repository
-		RemoteName string
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		want   *model.RemoteMutationResult
-	}{
-		{name: "Test for remote deletion", fields: struct {
-			Repo       git.Repository
-			RemoteName string
-		}{Repo: *r, RemoteName: testRemoteName}, want: &model.RemoteMutationResult{Status: global.RemoteDeleteSuccess}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			remoteObj := remote.NewDeleteRemoteInterface(&tt.fields.Repo, tt.fields.RemoteName)
-			got := remoteObj.DeleteRemote()
-
-			assert.Equal(t, tt.want.Status, got.Status)
-		})
-	}
-}

From c147adb17a4367747aaf2b064b007dfe4b9cbed2 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 25 Jun 2021 00:04:35 +0530
Subject: [PATCH 018/148] reduce verbosity in README

---
 README.md                              | 144 +++----------------------
 git/remote/git_remote_url_data_test.go |   2 +
 2 files changed, 15 insertions(+), 131 deletions(-)
 create mode 100644 git/remote/git_remote_url_data_test.go

diff --git a/README.md b/README.md
index 253b468..b141886 100644
--- a/README.md
+++ b/README.md
@@ -12,12 +12,9 @@ This is the back-end go source repo for the [gitconvex](https://github.com/neel1
 
 ## Dependencies
 
-The dependency packages used by this project can be
-found [here](https://github.com/neel1996/gitconvex-server/network/dependencies)
-
-- **📜 Git Library** - The project uses [git2go](https://github.com/libgit2/git2go) library for all the git operations
-  without relying on the native git client
-- **📈 GraphQL** - [gqlgen](https://github.com/99designs/gqlgen) is used for generating boiler plate GraphQL code which
+- **📜 Git Library** - The project uses [git2go](https://github.com/libgit2/git2go) library for performing all the git
+  operations
+- **📈 GraphQL** - [gqlgen](https://github.com/99designs/gqlgen) is used for generating boiler-plate GraphQL code which
   is the backbone of the whole project
 - **📡 HTTP Router** - [mux](https://github.com/gorilla/mux) is used as the HTTP router for graphql playground and sets
   a handler for the API entry point
@@ -28,139 +25,24 @@ The project uses **git2go** - A libgit2 based binding for go to handle all the g
 properly to run the project.
 
 Follow [these](https://libgit2.org/docs/guides/build-and-link/) instructions to build libgit2
-from [soruce](https://github.com/libgit2/libgit2). Follow this only if you have openssl and libssh setup in your
-machine. If this is not the case then follow the detailed instructions mentioned in [LIBGIT_NOTES](LIBGIT_NOTES.md) for a
-step-by-step guide
+from [source](https://github.com/libgit2/libgit2). Follow this only if you have openssl and libssh setup in your
+machine. If this is not the case then follow the detailed instructions mentioned in [LIBGIT_NOTES](LIBGIT_NOTES.md) for
+a step-by-step guide
 
 If you stumble upon any challenges, then use [this](https://github.com/neel1996/gitconvex-server/discussions/7)
 discussion forum for assistance
 
 ### Contribution Guidelines
 
-Fork the repo and raise a new Pull Request to merge your branch with the `main` branch of this repo. Once the
-review is complete, the PR will be approved and merged
+Fork the repo and raise a new Pull Request to merge your changes with the `main` branch of this repo. Once the review is
+complete, the PR will be approved and merged
 
 ## Gitconvex as a Git API
 
-Gitconvex can function as a service without the UI. The whole API is built with graphql and the underlying queries & mutations can be accessed by invoking `http://localhost:9001/gitconvexapi`. GraphQL playground is also enabled to experiment with the GQL queries and mutations and it can be accessed from `http://localhost:9001/gitconvexapi/graph`
-
-![gql-playground](https://user-images.githubusercontent.com/47709856/113421107-248f5100-93e8-11eb-8c22-9f6337f7c25f.png)
-
-## Project directory tree
-
-**📂 api** - All the common api modules which does not modify the git repo in anyway resides in this directory
-
-**📂 git** - The files in this directory will handle all the git related operations behind the scenes using `go-git` and
-the native `git` client
+Gitconvex can function as a service without the UI. The whole API is build with graphql, and the underlying
+queries/mutations can be accessed by invoking `http://localhost:9001/gitconvexapi`.
 
-**📂 graph** - The GQL schema and other files which are used for enabling GQL based communication are included in this
-directory.
-
-**📂 tests** - As the name suggests, all the test scripts are stored here
-
-**📂 utils** - The common utility modules which are required by other functions to execute common tasks are stored in
-this directory
-
-```
-├── api
-│   ├── add_repo.go
-│   ├── code_file_view.go
-│   ├── fetch_repo.go
-│   ├── health_check.go
-│   ├── repo_status.go
-│   ├── settings_api.go
-│   └── update_repo_name.go
-├── etc
-│   ├── cygwin1.dll
-│   ├── git2.dll
-│   ├── pageant.exe
-│   ├── putty.exe
-│   └── puttygen.exe
-├── git
-│   ├── git_branch_add.go
-│   ├── git_branch_checkout.go
-│   ├── git_branch_compare.go
-│   ├── git_branch_delete.go
-│   ├── git_branch_list.go
-│   ├── git_changed_files.go
-│   ├── git_clone.go
-│   ├── git_commit_changes.go
-│   ├── git_commit_compare.go
-│   ├── git_commit_files.go
-│   ├── git_commit_log_search.go
-│   ├── git_commit_logs.go
-│   ├── git_fetch.go
-│   ├── git_fileline_diff.go
-│   ├── git_init.go
-│   ├── git_ls_files.go
-│   ├── git_pull.go
-│   ├── git_push.go
-│   ├── git_remote_add.go
-│   ├── git_remote_allremotedata.go
-│   ├── git_remote_callbacks.go
-│   ├── git_remote_delete.go
-│   ├── git_remote_edit.go
-│   ├── git_repo.go
-│   ├── git_repo_validate.go
-│   ├── git_reset_item.go
-│   ├── git_resetall_items.go
-│   ├── git_stage_item.go
-│   ├── git_stageall_items.go
-│   ├── git_total_commits.go
-│   └── git_unpushed_commits.go
-├── gitconvex-k8s.yml
-├── gitconvex-ui
-├── global
-│   ├── GlobalLogger.go
-│   ├── common_strings.go
-│   ├── current_version.go
-│   ├── errors.go
-│   └── status_strings.go
-├── go.mod
-├── go.sum
-├── gqlgen.yml
-├── graph
-│   ├── generated
-│   │   └── generated.go
-│   ├── model
-│   │   ├── aux_models.go
-│   │   └── models_gen.go
-│   ├── resolver.go
-│   ├── schema.graphqls
-│   └── schema.resolvers.go
-├── make.bat
-├── server.go
-├── tests
-│   ├── beforeAll_git_clone_test.go
-│   ├── code_file_view_test.go
-│   ├── encrypt_https_password_test.go
-│   ├── git_branch_add_test.go
-│   ├── git_branch_delete_test.go
-│   ├── git_branch_test.go
-│   ├── git_changed_files_test.go
-│   ├── git_commit_changes_test.go
-│   ├── git_commit_compare_test.go
-│   ├── git_commit_files_test.go
-│   ├── git_commit_log_search_test.go
-│   ├── git_commit_logs_test.go
-│   ├── git_ls_files_test.go
-│   ├── git_remote_add_test.go
-│   ├── git_remote_allremotedata_test.go
-│   ├── git_remote_data_test.go
-│   ├── git_remote_delete_test.go
-│   ├── git_remote_edit_test.go
-│   ├── git_resetall_items_test.go
-│   ├── git_total_commits_test.go
-│   ├── git_unpushed_commits_test.go
-│   ├── health_check_test.go
-│   └── update_repo_name_test.go
-└── utils
-    ├── db_file_reader.go
-    ├── db_file_writer.go
-    ├── encrypt_https_password.go
-    ├── env_file_handler.go
-    └── git_standalone_client.go
-
-10 directories, 88 files
-```
+GraphQL playground is enabled to experiment with the GQL queries and mutations. It can be accessed
+from `http://localhost:9001/gitconvexapi/graph`
 
+![gql-playground](https://user-images.githubusercontent.com/47709856/113421107-248f5100-93e8-11eb-8c22-9f6337f7c25f.png)
diff --git a/git/remote/git_remote_url_data_test.go b/git/remote/git_remote_url_data_test.go
new file mode 100644
index 0000000..1cb8b88
--- /dev/null
+++ b/git/remote/git_remote_url_data_test.go
@@ -0,0 +1,2 @@
+package remote
+

From d425f2fc4d5949ac08598495b58748e111af3417 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 25 Jun 2021 01:01:17 +0530
Subject: [PATCH 019/148] create standalone package for all remote operations

---
 git/remote/git_remote_get_host.go         | 27 +++++++++
 git/remote/git_remote_get_host_test.go    | 33 +++++++++++
 git/remote/git_remote_list.go             | 71 +++++++++++++++++++++++
 git/remote/git_remote_list_test.go        | 55 ++++++++++++++++++
 git/remote/git_remote_remote_name.go      | 62 ++++++++++++++++++++
 git/remote/git_remote_remote_name_test.go | 44 ++++++++++++++
 git/remote/git_remote_url_data.go         | 64 ++++++++++++++++++++
 git/remote/git_remote_url_data_test.go    | 45 ++++++++++++++
 git/remote/remote.go                      | 64 +++++++++++++++++---
 tests/git_remote_edit_test.go             |  2 +-
 10 files changed, 458 insertions(+), 9 deletions(-)
 create mode 100644 git/remote/git_remote_get_host.go
 create mode 100644 git/remote/git_remote_get_host_test.go
 create mode 100644 git/remote/git_remote_remote_name.go
 create mode 100644 git/remote/git_remote_remote_name_test.go
 create mode 100644 git/remote/git_remote_url_data.go

diff --git a/git/remote/git_remote_get_host.go b/git/remote/git_remote_get_host.go
new file mode 100644
index 0000000..e52b685
--- /dev/null
+++ b/git/remote/git_remote_get_host.go
@@ -0,0 +1,27 @@
+package remote
+
+import "strings"
+
+type Host interface {
+	GetRemoteHostForUrl() string
+}
+
+type host struct {
+	remoteUrl string
+}
+
+func (h host) GetRemoteHostForUrl() string {
+	var remoteHostNames = []string{"github", "gitlab", "bitbucket", "azure", "codecommit"}
+
+	for _, hostName := range remoteHostNames {
+		if strings.Contains(h.remoteUrl, hostName) {
+			return hostName
+		}
+	}
+
+	return ""
+}
+
+func NewRemoteHost(remoteUrl string) Host {
+	return host{remoteUrl: remoteUrl}
+}
diff --git a/git/remote/git_remote_get_host_test.go b/git/remote/git_remote_get_host_test.go
new file mode 100644
index 0000000..1a08c8d
--- /dev/null
+++ b/git/remote/git_remote_get_host_test.go
@@ -0,0 +1,33 @@
+package remote
+
+import (
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type RemoteHostTestSuite struct {
+	suite.Suite
+	host Host
+}
+
+func TestRemoteHostTestSuite(t *testing.T) {
+	suite.Run(t, new(RemoteHostTestSuite))
+}
+
+func (suite *RemoteHostTestSuite) SetupTest() {
+	suite.host = NewRemoteHost("https://github.com/test/test.git")
+}
+
+func (suite *RemoteHostTestSuite) TestGetRemoteHost_WhenRemoteUrlIsPassed_ShouldReturnHostName() {
+	expectedHost := "github"
+	remoteHost := suite.host.GetRemoteHostForUrl()
+
+	suite.Equal(expectedHost, remoteHost)
+}
+
+func (suite *RemoteHostTestSuite) TestGetRemoteHost_WhenRemoteUrlContainsUnknownHost_ShouldReturnEmptyString() {
+	suite.host = NewRemoteHost("https://orca.com/test/test.git")
+	remoteHost := suite.host.GetRemoteHostForUrl()
+
+	suite.Equal("", remoteHost)
+}
diff --git a/git/remote/git_remote_list.go b/git/remote/git_remote_list.go
index fbe5b64..35b9bc6 100644
--- a/git/remote/git_remote_list.go
+++ b/git/remote/git_remote_list.go
@@ -1 +1,72 @@
 package remote
+
+import (
+	"errors"
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type List interface {
+	GetAllRemotes() []*model.RemoteDetails
+}
+
+type listRemotes struct {
+	repo *git2go.Repository
+}
+
+func (l listRemotes) GetAllRemotes() []*model.RemoteDetails {
+	var remoteList []*model.RemoteDetails
+	repo := l.repo
+
+	if validationErr := l.validateRepo(repo); validationErr != nil {
+		return nil
+	}
+
+	list, listErr := repo.Remotes.List()
+	if listErr != nil {
+		logger.Log(listErr.Error(), global.StatusError)
+		return nil
+	}
+
+	for _, remoteEntry := range list {
+		remote, remoteErr := repo.Remotes.Lookup(remoteEntry)
+		if remoteErr != nil {
+			logger.Log(remoteErr.Error(), global.StatusError)
+			continue
+		}
+
+		data := model.RemoteDetails{
+			RemoteName: remote.Name(),
+			RemoteURL:  remote.Url(),
+		}
+		remoteList = append(remoteList, &data)
+	}
+
+	if len(remoteList) == 0 {
+		logger.Log(fmt.Sprintf("No remotes available for the repo"), global.StatusWarning)
+		return nil
+	}
+
+	logger.Log(fmt.Sprintf("Remote data fetched => %+v", remoteList), global.StatusInfo)
+
+	return remoteList
+}
+
+func (l listRemotes) validateRepo(repo *git2go.Repository) error {
+	if repo == nil {
+		logger.Log("Repo is nil", global.StatusError)
+		return errors.New("repo is nil")
+	}
+
+	if repo.Remotes == (git2go.RemoteCollection{}) {
+		logger.Log("Remote collection is nil", global.StatusError)
+		return errors.New("repo remote collection is nil")
+	}
+	return nil
+}
+
+func NewRemoteList(repo *git2go.Repository) List {
+	return listRemotes{repo: repo}
+}
diff --git a/git/remote/git_remote_list_test.go b/git/remote/git_remote_list_test.go
index fbe5b64..2ff1903 100644
--- a/git/remote/git_remote_list_test.go
+++ b/git/remote/git_remote_list_test.go
@@ -1 +1,56 @@
 package remote
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/graph/model"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type ListRemoteTestSuite struct {
+	suite.Suite
+	listRemote List
+}
+
+func (suite *ListRemoteTestSuite) SetupTest() {
+	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	suite.listRemote = NewRemoteList(r)
+}
+
+func TestListRemoteTestSuite(t *testing.T) {
+	suite.Run(t, new(ListRemoteTestSuite))
+}
+
+func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsValid_ShouldReturnAllRemotes() {
+	expectedRemotes := []*model.RemoteDetails{{
+		RemoteName: "origin",
+		RemoteURL:  "https://github.com/neel1996/gitconvex-test.git",
+	}}
+
+	remoteList := suite.listRemote.GetAllRemotes()
+
+	suite.Equal(len(expectedRemotes), len(remoteList))
+	suite.Equal(expectedRemotes[0].RemoteName, remoteList[0].RemoteName)
+	suite.Equal(expectedRemotes[0].RemoteURL, remoteList[0].RemoteURL)
+}
+
+func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsNil_ShouldReturnNil() {
+	suite.listRemote = NewRemoteList(nil)
+
+	remoteList := suite.listRemote.GetAllRemotes()
+
+	suite.Nil(remoteList)
+}
+
+func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoHasNoRemotes_ShouldReturnNil() {
+	r := &git2go.Repository{
+		Remotes: git2go.RemoteCollection{},
+	}
+
+	suite.listRemote = NewRemoteList(r)
+
+	remoteList := suite.listRemote.GetAllRemotes()
+
+	suite.Nil(remoteList)
+}
diff --git a/git/remote/git_remote_remote_name.go b/git/remote/git_remote_remote_name.go
new file mode 100644
index 0000000..4eb8a49
--- /dev/null
+++ b/git/remote/git_remote_remote_name.go
@@ -0,0 +1,62 @@
+package remote
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type Name interface {
+	GetRemoteNameWithUrl() string
+}
+
+type remoteName struct {
+	repo      *git2go.Repository
+	remoteUrl string
+}
+
+func (r remoteName) GetRemoteNameWithUrl() string {
+	repo := r.repo
+
+	if repo == nil {
+		logger.Log("Repo is nil", global.StatusError)
+		return ""
+	}
+
+	remoteList, remoteListError := repo.Remotes.List()
+	if remoteListError != nil {
+		logger.Log(remoteListError.Error(), global.StatusError)
+		return ""
+	}
+
+	for _, remote := range remoteList {
+		remoteEntry, remoteLookupErr := repo.Remotes.Lookup(remote)
+		if remoteLookupErr != nil {
+			logger.Log(remoteLookupErr.Error(), global.StatusError)
+			continue
+		}
+
+		isRemotePresent := r.isRemoteAvailable(remoteEntry, remote)
+		if isRemotePresent {
+			logger.Log("Matching remote found for the URL", global.StatusInfo)
+			return remote
+		}
+	}
+
+	return ""
+}
+
+func (r remoteName) isRemoteAvailable(remoteEntry *git2go.Remote, remote string) bool {
+	if remoteEntry.Url() == r.remoteUrl {
+		logger.Log(fmt.Sprintf("Remote - %s found for the url - %s", remote, r.remoteUrl), global.StatusInfo)
+		return true
+	}
+	return false
+}
+
+func NewGetRemoteName(repo *git2go.Repository, remoteUrl string) Name {
+	return remoteName{
+		repo:      repo,
+		remoteUrl: remoteUrl,
+	}
+}
diff --git a/git/remote/git_remote_remote_name_test.go b/git/remote/git_remote_remote_name_test.go
new file mode 100644
index 0000000..b63ed0c
--- /dev/null
+++ b/git/remote/git_remote_remote_name_test.go
@@ -0,0 +1,44 @@
+package remote
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type GetRemoteNameTestSuite struct {
+	suite.Suite
+	getRemoteName Name
+	repo          *git2go.Repository
+}
+
+func (suite *GetRemoteNameTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.getRemoteName = NewGetRemoteName(r, "https://github.com/neel1996/gitconvex-test.git")
+}
+
+func TestGetRemoteNameTestSuite(t *testing.T) {
+	suite.Run(t, new(GetRemoteNameTestSuite))
+}
+
+func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnRemoteName_WhenRemoteUrlIsValid() {
+	expectedRemote := "origin"
+
+	actualRemote := suite.getRemoteName.GetRemoteNameWithUrl()
+
+	suite.Equal(expectedRemote, actualRemote)
+}
+
+func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_WhenRepoIsNil() {
+	expectedRemote := ""
+	getRemoteName := NewGetRemoteName(nil, "https://github.com/neel1996/gitconvex-test.git")
+
+	actualRemote := getRemoteName.GetRemoteNameWithUrl()
+
+	suite.Equal(expectedRemote, actualRemote)
+}
diff --git a/git/remote/git_remote_url_data.go b/git/remote/git_remote_url_data.go
new file mode 100644
index 0000000..5411687
--- /dev/null
+++ b/git/remote/git_remote_url_data.go
@@ -0,0 +1,64 @@
+package remote
+
+import (
+	"errors"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type ListRemoteUrl interface {
+	GetAllRemoteUrl() []*string
+}
+
+type listRemoteUrl struct {
+	repo *git2go.Repository
+}
+
+func (u listRemoteUrl) GetAllRemoteUrl() []*string {
+	var remoteURL []*string
+
+	repo := u.repo
+
+	if validationErr := u.validateFields(repo); validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return nil
+	}
+
+	remotes, listErr := repo.Remotes.List()
+	if listErr != nil {
+		logger.Log(listErr.Error(), global.StatusError)
+		return nil
+	}
+
+	for _, remoteName := range remotes {
+		remote, _ := repo.Remotes.Lookup(remoteName)
+		if remote != nil {
+			url := remote.Url()
+			remoteURL = append(remoteURL, &url)
+		}
+	}
+
+	if len(remoteURL) == 0 {
+		logger.Log("No remotes present in the repo", global.StatusError)
+		return nil
+	}
+
+	return remoteURL
+}
+
+func (u listRemoteUrl) validateFields(repo *git2go.Repository) error {
+	if repo == nil {
+		return errors.New("repo is nil")
+	}
+
+	remoteCollection := repo.Remotes
+	if remoteCollection == (git2go.RemoteCollection{}) {
+		return errors.New("remote collection is empty")
+	}
+
+	return nil
+}
+
+func NewRemoteUrlData(repo *git2go.Repository) ListRemoteUrl {
+	return listRemoteUrl{repo: repo}
+}
diff --git a/git/remote/git_remote_url_data_test.go b/git/remote/git_remote_url_data_test.go
index 1cb8b88..507d039 100644
--- a/git/remote/git_remote_url_data_test.go
+++ b/git/remote/git_remote_url_data_test.go
@@ -1,2 +1,47 @@
 package remote
 
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type RemoteUrlDataTestSuite struct {
+	suite.Suite
+	listRemoteUrl ListRemoteUrl
+}
+
+func TestRemoteUrlDataTestSuite(t *testing.T) {
+	suite.Run(t, new(RemoteUrlDataTestSuite))
+}
+
+func (suite *RemoteUrlDataTestSuite) SetupTest() {
+	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	suite.listRemoteUrl = NewRemoteUrlData(r)
+}
+
+func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesArePresent_ShouldReturnRemoteUrlList() {
+	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
+
+	suite.NotZero(len(urlList))
+	suite.Equal("https://github.com/neel1996/gitconvex-test.git", *urlList[0])
+}
+
+func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoIsNil_ShouldReturnNil() {
+	suite.listRemoteUrl = NewRemoteUrlData(nil)
+
+	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
+
+	suite.Nil(urlList)
+}
+
+func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesAreNil_ShouldReturnNil() {
+	suite.listRemoteUrl = NewRemoteUrlData(&git2go.Repository{
+		Remotes: git2go.RemoteCollection{},
+	})
+
+	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
+
+	suite.Nil(urlList)
+}
diff --git a/git/remote/remote.go b/git/remote/remote.go
index c71e06b..7a4bba4 100644
--- a/git/remote/remote.go
+++ b/git/remote/remote.go
@@ -11,29 +11,77 @@ var logger global.Logger
 type Remote interface {
 	GitAddRemote() (*model.RemoteMutationResult, error)
 	GitDeleteRemote() (*model.RemoteMutationResult, error)
+	GitGetAllRemote() ([]*model.RemoteDetails, error)
+	GitGetRemoteHostName() (string, error)
+	GitRemoteName() (string, error)
+	GitGetAllRemoteUrl() ([]*string, error)
 }
 
 type Operation struct {
-	Add    Add
-	Delete Delete
+	Add           Add
+	Delete        Delete
+	Host          Host
+	List          List
+	Name          Name
+	ListRemoteUrl ListRemoteUrl
 }
 
 func (r Operation) GitAddRemote() (*model.RemoteMutationResult, error) {
-	addRemoteResult := r.Add.NewRemote()
+	addRemoteErr := r.Add.NewRemote()
 
-	if addRemoteResult.Status == global.RemoteAddError {
+	if addRemoteErr != nil {
 		return nil, errors.New(global.RemoteAddError)
 	}
 
-	return addRemoteResult, nil
+	return &model.RemoteMutationResult{Status: global.RemoteAddSuccess}, nil
 }
 
 func (r Operation) GitDeleteRemote() (*model.RemoteMutationResult, error) {
-	deleteRemoteResult := r.Delete.DeleteRemote()
+	err := r.Delete.DeleteRemote()
 
-	if deleteRemoteResult.Status == global.RemoteDeleteError {
+	if err != nil {
 		return nil, errors.New(global.RemoteDeleteError)
 	}
 
-	return deleteRemoteResult, nil
+	return &model.RemoteMutationResult{Status: global.RemoteDeleteSuccess}, nil
+}
+
+func (r Operation) GitGetRemoteHostName() (string, error) {
+	remoteHost := r.Host.GetRemoteHostForUrl()
+
+	if remoteHost == "" {
+		return "", errors.New("unable to find a matching host name")
+	}
+
+	return remoteHost, nil
+}
+
+func (r Operation) GitGetAllRemote() ([]*model.RemoteDetails, error) {
+	allRemotes := r.List.GetAllRemotes()
+
+	if allRemotes == nil {
+		return nil, errors.New("unable to fetch remotes from the repo")
+	}
+
+	return allRemotes, nil
+}
+
+func (r Operation) GitRemoteName() (string, error) {
+	remoteHost := r.Name.GetRemoteNameWithUrl()
+
+	if remoteHost == "" {
+		return "", errors.New("no matching remote found for the URL")
+	}
+
+	return remoteHost, nil
+}
+
+func (r Operation) GitGetAllRemoteUrl() ([]*string, error) {
+	remoteUrlList := r.ListRemoteUrl.GetAllRemoteUrl()
+
+	if remoteUrlList == nil {
+		return nil, errors.New("unable to fetch remote URLs from the repo")
+	}
+
+	return remoteUrlList, nil
 }
diff --git a/tests/git_remote_edit_test.go b/tests/git_remote_edit_test.go
index 4b169e4..467c523 100644
--- a/tests/git_remote_edit_test.go
+++ b/tests/git_remote_edit_test.go
@@ -25,7 +25,7 @@ func TestRemoteEditStruct_EditRemoteUrl(t *testing.T) {
 			Repo       *git.Repository
 			RemoteName string
 			RemoteUrl  string
-		}{Repo: r, RemoteName: "origin", RemoteUrl: "git@github.com:neel1996/gitconvex-server.git"}, want: global.RemoteEditSuccess},
+		}{Repo: r, RemoteName: "origin", RemoteUrl: "https://github.com/neel1996/gitconvex-test.git"}, want: global.RemoteEditSuccess},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {

From 0ab0f9819dce53aba452da91ba8617811b8d09c0 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 25 Jun 2021 01:09:51 +0530
Subject: [PATCH 020/148] update delete remote call in gql resolver

---
 graph/schema.resolvers.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index 8ebfa3d..45f5f31 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -353,7 +353,7 @@ func (r *mutationResolver) DeleteRemote(ctx context.Context, repoID string, remo
 		return &model.RemoteMutationResult{Status: global.RemoteAddError}, nil
 	}
 
-	deleteRemote := remote.NewDeleteRemoteInterface(repo.GitRepo, remoteName)
+	deleteRemote := remote.NewDeleteRemote(repo.GitRepo, remoteName)
 	remoteObject := remote.Operation{
 		Delete: deleteRemote,
 	}

From f47f75dd877599db7d1dc06cd648e2f30a1f79a1 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 25 Jun 2021 10:17:57 +0530
Subject: [PATCH 021/148] modify test stage to run old and new test suite
 separately

---
 .github/workflows/go-collab.yml | 3 ++-
 .github/workflows/go.yml        | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index 6973867..febbf4d 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -45,7 +45,8 @@ jobs:
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
           go generate
-          go test -v ./...
+          go test ./tests -count=1 -v
+          go test $(go list ./... | grep -v "tests") -count=1 -v
 
   gitconvex-build:
     needs:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 6bbf0cd..ccd429d 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -45,7 +45,8 @@ jobs:
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
           go generate
-          go test -v ./...
+          go test ./tests -count=1 -v
+          go test $(go list ./... | grep -v "tests") -count=1 -v
 
   gitconvex-build:
     needs:

From 7367b965ebc7d38cc034c53107e6bc5291bd015a Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 26 Jun 2021 22:34:51 +0530
Subject: [PATCH 022/148] include remote edit into the standard remote package

---
 git/remote/git_remote_edit.go      | 68 ++++++++++++++++++++++++++++++
 git/remote/git_remote_edit_test.go | 60 ++++++++++++++++++++++++++
 2 files changed, 128 insertions(+)
 create mode 100644 git/remote/git_remote_edit.go
 create mode 100644 git/remote/git_remote_edit_test.go

diff --git a/git/remote/git_remote_edit.go b/git/remote/git_remote_edit.go
new file mode 100644
index 0000000..7f26107
--- /dev/null
+++ b/git/remote/git_remote_edit.go
@@ -0,0 +1,68 @@
+package remote
+
+import (
+	"errors"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type Edit interface {
+	EditRemote() error
+}
+
+type editRemote struct {
+	repo       *git2go.Repository
+	remoteName string
+	remoteURL  string
+}
+
+func (e editRemote) EditRemote() error {
+	repo := e.repo
+
+	validationErr := e.validateRemoteFields()
+	if validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return validationErr
+	}
+
+	remoteCollection := repo.Remotes
+	_, listErr := remoteCollection.List()
+
+	if listErr != nil {
+		logger.Log(listErr.Error(), global.StatusError)
+		return listErr
+	}
+
+	err := repo.Remotes.SetUrl(e.remoteName, e.remoteURL)
+
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return err
+	}
+
+	logger.Log("Remote data has been updated successfully", global.StatusInfo)
+	return nil
+}
+
+func (e editRemote) validateRemoteFields() error {
+	if e.repo == nil {
+		return errors.New("repo is nil")
+	}
+
+	if e.repo.Remotes == (git2go.RemoteCollection{}) {
+		return errors.New("remote collection is empty")
+	}
+
+	if e.remoteName == "" || e.remoteURL == "" {
+		return errors.New("required field(s) are empty")
+	}
+	return nil
+}
+
+func NewEditRemote(repo *git2go.Repository, remoteName string, remoteURL string) Edit {
+	return editRemote{
+		repo:       repo,
+		remoteName: remoteName,
+		remoteURL:  remoteURL,
+	}
+}
diff --git a/git/remote/git_remote_edit_test.go b/git/remote/git_remote_edit_test.go
new file mode 100644
index 0000000..a1d1da9
--- /dev/null
+++ b/git/remote/git_remote_edit_test.go
@@ -0,0 +1,60 @@
+package remote
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type RemoteEditTestSuite struct {
+	suite.Suite
+	repo       *git2go.Repository
+	editRemote Edit
+}
+
+func TestRemoteEditTestSuite(t *testing.T) {
+	suite.Run(t, new(RemoteEditTestSuite))
+}
+
+func (suite *RemoteEditTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = r
+	suite.editRemote = NewEditRemote(r, "origin", "https://github.com/neel1996/gitconvex-test.git")
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsEdited_ShouldReturnNil() {
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.Nil(wantErr)
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoIsNil_ShouldReturnError() {
+	suite.editRemote = NewEditRemote(nil, "origin", "https://github.com/neel1996/gitconvex-test.git")
+
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.NotNil(wantErr)
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteCollectionIsNil_ShouldReturnError() {
+	suite.editRemote = NewEditRemote(&git2go.Repository{
+		Remotes: git2go.RemoteCollection{},
+	}, "origin", "https://github.com/neel1996/gitconvex-test.git")
+
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.NotNil(wantErr)
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteEditFieldsAreEmpty_ShouldReturnError() {
+	suite.editRemote = NewEditRemote(suite.repo, "", "")
+
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.NotNil(wantErr)
+}

From d443e6be8fe318533114187b30a685e6d36dbd4f Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 26 Jun 2021 23:28:27 +0530
Subject: [PATCH 023/148] create new validation module for handling remote
 validations

---
 git/remote/git_remote_edit.go        | 14 ++++----
 git/remote/git_remote_edit_test.go   | 10 +++---
 git/remote/remote.go                 | 12 +++++++
 git/remote/remote_validation.go      | 50 ++++++++++++++++++++++++++
 git/remote/remote_validation_test.go | 54 ++++++++++++++++++++++++++++
 5 files changed, 128 insertions(+), 12 deletions(-)
 create mode 100644 git/remote/remote_validation.go
 create mode 100644 git/remote/remote_validation_test.go

diff --git a/git/remote/git_remote_edit.go b/git/remote/git_remote_edit.go
index 7f26107..4c7fda3 100644
--- a/git/remote/git_remote_edit.go
+++ b/git/remote/git_remote_edit.go
@@ -14,6 +14,7 @@ type editRemote struct {
 	repo       *git2go.Repository
 	remoteName string
 	remoteURL  string
+	validate   Validation
 }
 
 func (e editRemote) EditRemote() error {
@@ -34,7 +35,6 @@ func (e editRemote) EditRemote() error {
 	}
 
 	err := repo.Remotes.SetUrl(e.remoteName, e.remoteURL)
-
 	if err != nil {
 		logger.Log(err.Error(), global.StatusError)
 		return err
@@ -45,12 +45,9 @@ func (e editRemote) EditRemote() error {
 }
 
 func (e editRemote) validateRemoteFields() error {
-	if e.repo == nil {
-		return errors.New("repo is nil")
-	}
-
-	if e.repo.Remotes == (git2go.RemoteCollection{}) {
-		return errors.New("remote collection is empty")
+	validationError := e.validate.ValidateRemoteFields(e.repo)
+	if validationError != nil {
+		return validationError
 	}
 
 	if e.remoteName == "" || e.remoteURL == "" {
@@ -59,10 +56,11 @@ func (e editRemote) validateRemoteFields() error {
 	return nil
 }
 
-func NewEditRemote(repo *git2go.Repository, remoteName string, remoteURL string) Edit {
+func NewEditRemote(repo *git2go.Repository, remoteName string, remoteURL string, validation Validation) Edit {
 	return editRemote{
 		repo:       repo,
 		remoteName: remoteName,
 		remoteURL:  remoteURL,
+		validate:   validation,
 	}
 }
diff --git a/git/remote/git_remote_edit_test.go b/git/remote/git_remote_edit_test.go
index a1d1da9..ffec866 100644
--- a/git/remote/git_remote_edit_test.go
+++ b/git/remote/git_remote_edit_test.go
@@ -11,6 +11,7 @@ import (
 type RemoteEditTestSuite struct {
 	suite.Suite
 	repo       *git2go.Repository
+	validation Validation
 	editRemote Edit
 }
 
@@ -24,7 +25,8 @@ func (suite *RemoteEditTestSuite) SetupTest() {
 		fmt.Println(err)
 	}
 	suite.repo = r
-	suite.editRemote = NewEditRemote(r, "origin", "https://github.com/neel1996/gitconvex-test.git")
+	suite.validation = NewRemoteValidation()
+	suite.editRemote = NewEditRemote(r, "origin", "https://github.com/neel1996/gitconvex-test.git", suite.validation)
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsEdited_ShouldReturnNil() {
@@ -34,7 +36,7 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsEdited_ShouldReturn
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoIsNil_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(nil, "origin", "https://github.com/neel1996/gitconvex-test.git")
+	suite.editRemote = NewEditRemote(nil, "origin", "https://github.com/neel1996/gitconvex-test.git", suite.validation)
 
 	wantErr := suite.editRemote.EditRemote()
 
@@ -44,7 +46,7 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoIsNil_ShouldReturnError
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteCollectionIsNil_ShouldReturnError() {
 	suite.editRemote = NewEditRemote(&git2go.Repository{
 		Remotes: git2go.RemoteCollection{},
-	}, "origin", "https://github.com/neel1996/gitconvex-test.git")
+	}, "origin", "https://github.com/neel1996/gitconvex-test.git", suite.validation)
 
 	wantErr := suite.editRemote.EditRemote()
 
@@ -52,7 +54,7 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteCollectionIsNil_Shoul
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteEditFieldsAreEmpty_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(suite.repo, "", "")
+	suite.editRemote = NewEditRemote(suite.repo, "", "", suite.validation)
 
 	wantErr := suite.editRemote.EditRemote()
 
diff --git a/git/remote/remote.go b/git/remote/remote.go
index 7a4bba4..8a6e939 100644
--- a/git/remote/remote.go
+++ b/git/remote/remote.go
@@ -11,6 +11,7 @@ var logger global.Logger
 type Remote interface {
 	GitAddRemote() (*model.RemoteMutationResult, error)
 	GitDeleteRemote() (*model.RemoteMutationResult, error)
+	GitEditRemote() (*model.RemoteMutationResult, error)
 	GitGetAllRemote() ([]*model.RemoteDetails, error)
 	GitGetRemoteHostName() (string, error)
 	GitRemoteName() (string, error)
@@ -20,6 +21,7 @@ type Remote interface {
 type Operation struct {
 	Add           Add
 	Delete        Delete
+	Edit          Edit
 	Host          Host
 	List          List
 	Name          Name
@@ -46,6 +48,16 @@ func (r Operation) GitDeleteRemote() (*model.RemoteMutationResult, error) {
 	return &model.RemoteMutationResult{Status: global.RemoteDeleteSuccess}, nil
 }
 
+func (r Operation) GitEditRemote() (*model.RemoteMutationResult, error) {
+	err := r.Edit.EditRemote()
+
+	if err != nil {
+		return nil, err
+	}
+
+	return &model.RemoteMutationResult{Status: global.RemoteEditSuccess}, nil
+}
+
 func (r Operation) GitGetRemoteHostName() (string, error) {
 	remoteHost := r.Host.GetRemoteHostForUrl()
 
diff --git a/git/remote/remote_validation.go b/git/remote/remote_validation.go
new file mode 100644
index 0000000..23d4c15
--- /dev/null
+++ b/git/remote/remote_validation.go
@@ -0,0 +1,50 @@
+package remote
+
+import (
+	"errors"
+	git2go "github.com/libgit2/git2go/v31"
+)
+
+type Validation interface {
+	ValidateRemoteFields(*git2go.Repository) error
+}
+
+type validation struct {
+	repo *git2go.Repository
+}
+
+func (v validation) ValidateRemoteFields(repository *git2go.Repository) error {
+	v.repo = repository
+
+	validateRepoErr := v.validateRepo()
+	if validateRepoErr != nil {
+		return validateRepoErr
+	}
+
+	validateRemotesErr := v.validateRemoteCollection()
+	if validateRemotesErr != nil {
+		return validateRemotesErr
+	}
+
+	return nil
+}
+
+func (v validation) validateRepo() error {
+	if v.repo == nil {
+		return errors.New("repo is nil")
+	}
+
+	return nil
+}
+
+func (v validation) validateRemoteCollection() error {
+	if v.repo.Remotes == (git2go.RemoteCollection{}) {
+		return errors.New("remote collection is nil")
+	}
+
+	return nil
+}
+
+func NewRemoteValidation() Validation {
+	return validation{}
+}
diff --git a/git/remote/remote_validation_test.go b/git/remote/remote_validation_test.go
new file mode 100644
index 0000000..4456392
--- /dev/null
+++ b/git/remote/remote_validation_test.go
@@ -0,0 +1,54 @@
+package remote
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type RemoteValidationTestSuite struct {
+	suite.Suite
+	repo                 *git2go.Repository
+	validateRemoteFields Validation
+}
+
+func TestRemoteValidationTestSuite(t *testing.T) {
+	suite.Run(t, new(RemoteValidationTestSuite))
+}
+
+func (suite *RemoteValidationTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = r
+	suite.validateRemoteFields = NewRemoteValidation()
+}
+
+func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenAllFieldsAreValid_ShouldReturnNil() {
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields(suite.repo)
+
+	fmt.Println(wantErr)
+
+	suite.Nil(wantErr)
+}
+
+func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRepoIsNil_ShouldReturnError() {
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields(nil)
+	wantErrorText := "repo is nil"
+
+	suite.NotNil(wantErr)
+	suite.Equal(wantErrorText, wantErr.Error())
+}
+
+func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRemoteCollectionIsNil_ShouldReturnError() {
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields(&git2go.Repository{
+		Remotes: git2go.RemoteCollection{},
+	})
+	wantErrorText := "remote collection is nil"
+
+	suite.NotNil(wantErr)
+	suite.Equal(wantErrorText, wantErr.Error())
+}

From 048b96d7a77dece4a6a6fe8728187ac014fd7849 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 27 Jun 2021 23:31:51 +0530
Subject: [PATCH 024/148] add complete remote suite into stand-alone package
 with tests

---
 api/repo_status.go                        |  33 +++---
 git/git_fetch.go                          |   9 +-
 git/git_pull.go                           |   9 +-
 git/git_remote_allremotedata.go           | 123 ----------------------
 git/git_remote_edit.go                    |  43 --------
 git/remote/git_remote_add.go              |  13 ++-
 git/remote/git_remote_add_test.go         |  10 +-
 git/remote/git_remote_delete.go           |   4 +-
 git/remote/git_remote_delete_test.go      |   8 +-
 git/remote/git_remote_list.go             |  24 ++---
 git/remote/git_remote_list_test.go        |   8 +-
 git/remote/git_remote_remote_name.go      |   8 +-
 git/remote/git_remote_remote_name_test.go |   6 +-
 git/remote/git_remote_url_data.go         |  23 +---
 git/remote/git_remote_url_data_test.go    |  15 ++-
 graph/schema.resolvers.go                 |  75 +++++++------
 init/init_remote.go                       |  46 ++++++++
 tests/git_remote_allremotedata_test.go    |  38 -------
 tests/git_remote_data_test.go             |  44 --------
 tests/git_remote_edit_test.go             |  42 --------
 20 files changed, 158 insertions(+), 423 deletions(-)
 delete mode 100644 git/git_remote_allremotedata.go
 delete mode 100644 git/git_remote_edit.go
 create mode 100644 init/init_remote.go
 delete mode 100644 tests/git_remote_allremotedata_test.go
 delete mode 100644 tests/git_remote_data_test.go
 delete mode 100644 tests/git_remote_edit_test.go

diff --git a/api/repo_status.go b/api/repo_status.go
index 216d066..2e94a73 100644
--- a/api/repo_status.go
+++ b/api/repo_status.go
@@ -3,6 +3,7 @@ package api
 import (
 	"github.com/neel1996/gitconvex/git"
 	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/remote"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/neel1996/gitconvex/utils"
@@ -14,7 +15,6 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	logger.Log("Collecting repo status information", global.StatusInfo)
 
 	repoChan := make(chan git.RepoDetails)
-	remoteChan := make(chan git.RemoteDataModel)
 	branchChan := make(chan branch.ListOfBranches)
 	commitChan := make(chan git.AllCommitData)
 	trackedFileCountChan := make(chan int)
@@ -41,21 +41,26 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 		}
 	}
 
-	remote := ""
-	var remoteURL *string
-	remoteURL = &remote
-
-	var remoteDataObject git.RemoteDataInterface
-	remoteDataObject = git.RemoteDataStruct{
-		Repo:      repo,
-		RemoteURL: *remoteURL,
+	tempRemote := ""
+	var (
+		remoteURL  *string
+		remoteName string
+	)
+	remoteURL = &tempRemote
+
+	remoteValidation := remote.NewRemoteValidation()
+	remoteUrlList := remote.NewRemoteUrlData(repo, remoteValidation)
+	listRemoteUrl := remote.Operation{ListRemoteUrl: remoteUrlList}
+
+	remotes, remoteErr := listRemoteUrl.GitGetAllRemoteUrl()
+	if remoteErr != nil {
+		logger.Log(remoteErr.Error(), global.StatusError)
+		return nil
 	}
 
-	go remoteDataObject.RemoteData(remoteChan)
-	remoteData := <-remoteChan
-	remotes := remoteData.RemoteURL
-
 	if len(remotes) > 0 && *remotes[0] != "" {
+		remoteNameObject := remote.NewGetRemoteName(repo, *remotes[0], remoteValidation)
+		remoteName = remoteNameObject.GetRemoteNameWithUrl()
 		sRemote := strings.Split(*remotes[0], "/")
 		repoName = &sRemote[len(sRemote)-1]
 	} else {
@@ -115,7 +120,7 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 		GitBranchList:        branches,
 		GitAllBranchList:     allBranches,
 		GitCurrentBranch:     currentBranch,
-		GitRemoteHost:        remoteData.RemoteHost,
+		GitRemoteHost:        &remoteName,
 		GitTotalCommits:      totalCommitsPtr,
 		GitLatestCommit:      latestCommit,
 		GitTotalTrackedFiles: trackedFilePtr,
diff --git a/git/git_fetch.go b/git/git_fetch.go
index a8f8ca7..12fbc16 100644
--- a/git/git_fetch.go
+++ b/git/git_fetch.go
@@ -28,16 +28,9 @@ type FetchStruct struct {
 // If the remoteBranch is empty, then a fetch is performed with no branch name (similar to `git fetch`)
 func (f FetchStruct) FetchFromRemote() *model.FetchResult {
 	repo := f.Repo
-	remoteURL := f.RemoteURL
 	remoteBranch := f.RemoteBranch
+	remoteName := f.RemoteName
 
-	var remoteDataObject RemoteDataInterface
-	remoteDataObject = RemoteDataStruct{
-		Repo:      repo,
-		RemoteURL: remoteURL,
-	}
-
-	remoteName := remoteDataObject.GetRemoteName()
 	localRefSpec := "+refs/heads/" + remoteBranch
 	targetRefPsec := "refs/remotes/" + remoteName + "/" + remoteBranch
 	targetRemote, _ := repo.Remotes.Lookup(remoteName)
diff --git a/git/git_pull.go b/git/git_pull.go
index b5ecb1c..17ac9a7 100644
--- a/git/git_pull.go
+++ b/git/git_pull.go
@@ -36,15 +36,8 @@ func returnPullErr(msg string) *model.PullResult {
 func (p PullStruct) PullFromRemote() *model.PullResult {
 	repo := p.Repo
 	remoteBranch := p.RemoteBranch
-	remoteURL := p.RemoteURL
+	remoteName := p.RemoteName
 
-	var remoteDataObject RemoteDataInterface
-	remoteDataObject = RemoteDataStruct{
-		Repo:      repo,
-		RemoteURL: remoteURL,
-	}
-
-	remoteName := remoteDataObject.GetRemoteName()
 	localRefSpec := "+refs/heads/" + remoteBranch
 	targetRefPsec := "refs/remotes/" + remoteName + "/" + remoteBranch
 	targetRemote, _ := repo.Remotes.Lookup(remoteName)
diff --git a/git/git_remote_allremotedata.go b/git/git_remote_allremotedata.go
deleted file mode 100644
index 4118668..0000000
--- a/git/git_remote_allremotedata.go
+++ /dev/null
@@ -1,123 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-	"strings"
-)
-
-type RemoteDataInterface interface {
-	GetRemoteHost() *string
-	GetRemoteName() string
-	GetAllRemotes() []*model.RemoteDetails
-	RemoteData(remoteChan chan RemoteDataModel)
-}
-
-type RemoteDataStruct struct {
-	Repo      *git2go.Repository
-	RemoteURL string
-}
-
-type RemoteDataModel struct {
-	RemoteHost *string
-	RemoteURL  []*string
-}
-
-// GetRemoteHost returns the remote repository host name based on the remote URL
-// e.g. github.com/test.git => returns github
-func (r RemoteDataStruct) GetRemoteHost() *string {
-	remoteURL := r.RemoteURL
-	var remoteHostReference []string
-	remoteHostReference = []string{"github", "gitlab", "bitbucket", "azure", "codecommit"}
-
-	for _, host := range remoteHostReference {
-		if strings.Contains(remoteURL, host) {
-			return &host
-		}
-	}
-	return nil
-}
-
-// GetRemoteName function returns the name of the remote based on the supplied remote URL
-func (r RemoteDataStruct) GetRemoteName() string {
-	repo := r.Repo
-	remoteURL := r.RemoteURL
-	remoteList, _ := repo.Remotes.List()
-
-	for _, remoteEntry := range remoteList {
-		remoteCollection, _ := repo.Remotes.Lookup(remoteEntry)
-		if remoteCollection != nil {
-			url := remoteCollection.Url()
-			if url == remoteURL {
-				remoteName := remoteCollection.Name()
-				logger.Log(fmt.Sprintf("Remote Name - %s for the url - %s", remoteName, remoteURL), global.StatusInfo)
-				return remoteName
-			}
-		}
-	}
-	logger.Log(fmt.Sprintf("Unable to find a suitable remote entry for the url - %s", remoteURL), global.StatusError)
-	return ""
-}
-
-// RemoteData returns the remote host name and the remote URL of the target repo
-func (r RemoteDataStruct) RemoteData(remoteChan chan RemoteDataModel) {
-	var remoteURL []*string
-	repo := r.Repo
-
-	remotes, _ := repo.Remotes.List()
-
-	for _, i := range remotes {
-		remote, _ := repo.Remotes.Lookup(i)
-		if remote != nil {
-			url := remote.Url()
-			remoteURL = append(remoteURL, &url)
-		}
-	}
-
-	if len(remoteURL) == 0 {
-		nilRemote := "No Remote Host Available"
-		nilRemoteURL := ""
-		remoteChan <- RemoteDataModel{
-			RemoteHost: &nilRemote,
-			RemoteURL:  []*string{&nilRemoteURL},
-		}
-	} else {
-		r.RemoteURL = *remoteURL[0]
-		remoteChan <- RemoteDataModel{
-			RemoteHost: r.GetRemoteHost(),
-			RemoteURL:  remoteURL,
-		}
-	}
-	close(remoteChan)
-}
-
-// GetAllRemotes returns all the remotes and their corresponding URLs from the target repo
-func (r RemoteDataStruct) GetAllRemotes() []*model.RemoteDetails {
-	var allRemoteData []*model.RemoteDetails
-
-	repo := r.Repo
-	remoteList, remoteListErr := repo.Remotes.List()
-	if remoteListErr != nil {
-		logger.Log(remoteListErr.Error(), global.StatusError)
-		return nil
-	}
-
-	for _, remoteEntry := range remoteList {
-		if remoteEntry != "" {
-			remote, remoteErr := repo.Remotes.Lookup(remoteEntry)
-			if remoteErr != nil {
-				logger.Log(remoteErr.Error(), global.StatusError)
-				continue
-			}
-			data := model.RemoteDetails{
-				RemoteName: remote.Name(),
-				RemoteURL:  remote.Url(),
-			}
-			logger.Log(fmt.Sprintf("Remote data fetched => %+v", data), global.StatusInfo)
-			allRemoteData = append(allRemoteData, &data)
-		}
-	}
-	return allRemoteData
-}
diff --git a/git/git_remote_edit.go b/git/git_remote_edit.go
deleted file mode 100644
index 7ae4376..0000000
--- a/git/git_remote_edit.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-)
-
-type RemoteEditInterface interface {
-	EditRemoteUrl() *model.RemoteMutationResult
-}
-
-type RemoteEditStruct struct {
-	Repo          *git2go.Repository
-	RemoteName    string
-	NewRemoteName string
-	RemoteUrl     string
-}
-
-func (e RemoteEditStruct) EditRemoteUrl() *model.RemoteMutationResult {
-	repo := e.Repo
-	remoteName := e.RemoteName
-	remoteUrl := e.RemoteUrl
-
-	remoteCollection := repo.Remotes
-	_, listErr := remoteCollection.List()
-
-	if listErr != nil {
-		logger.Log(listErr.Error(), global.StatusError)
-		return &model.RemoteMutationResult{Status: global.RemoteEditError}
-	}
-
-	err := repo.Remotes.SetUrl(remoteName, remoteUrl)
-
-	if err != nil {
-		logger.Log(err.Error(), global.StatusError)
-		return &model.RemoteMutationResult{Status: global.RemoteEditError}
-	} else {
-		logger.Log(fmt.Sprintf("New URL has been set for the remote -> %s", remoteName), global.StatusInfo)
-		return &model.RemoteMutationResult{Status: global.RemoteEditSuccess}
-	}
-}
diff --git a/git/remote/git_remote_add.go b/git/remote/git_remote_add.go
index 0116539..11ff850 100644
--- a/git/remote/git_remote_add.go
+++ b/git/remote/git_remote_add.go
@@ -15,6 +15,7 @@ type addRemote struct {
 	repo       *git2go.Repository
 	remoteName string
 	remoteURL  string
+	validate   Validation
 }
 
 // NewRemote adds a new remote to the target git repo
@@ -35,12 +36,9 @@ func (a addRemote) NewRemote() error {
 }
 
 func (a addRemote) validateRemoteFields() error {
-	if a.repo == nil {
-		return errors.New("repo is nil")
-	}
-
-	if a.remoteName == "" {
-		return errors.New("remote name cannot be empty")
+	validationErr := a.validate.ValidateRemoteFields(a.repo)
+	if validationErr != nil {
+		return validationErr
 	}
 
 	if a.remoteURL == "" {
@@ -50,10 +48,11 @@ func (a addRemote) validateRemoteFields() error {
 	return nil
 }
 
-func NewAddRemote(repo *git2go.Repository, remoteName string, remoteURL string) Add {
+func NewAddRemote(repo *git2go.Repository, remoteName string, remoteURL string, validate Validation) Add {
 	return addRemote{
 		repo:       repo,
 		remoteName: remoteName,
 		remoteURL:  remoteURL,
+		validate:   validate,
 	}
 }
diff --git a/git/remote/git_remote_add_test.go b/git/remote/git_remote_add_test.go
index 6d5ec17..67c69ff 100644
--- a/git/remote/git_remote_add_test.go
+++ b/git/remote/git_remote_add_test.go
@@ -10,7 +10,8 @@ import (
 
 type RemoteAddTestSuite struct {
 	suite.Suite
-	addRemote Add
+	addRemote  Add
+	validation Validation
 }
 
 func TestRemoteAddTestSuite(t *testing.T) {
@@ -22,7 +23,8 @@ func (suite *RemoteAddTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.addRemote = NewAddRemote(r, "new_origin", "https://github.com/neel1996/gitconvex-test.git")
+	suite.validation = NewRemoteValidation()
+	suite.addRemote = NewAddRemote(r, "new_origin", "https://github.com/neel1996/gitconvex-test.git", suite.validation)
 }
 
 func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenNewRemoteIsAdded_ShouldReturnNoError() {
@@ -32,7 +34,7 @@ func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenNewRemoteIsAdded_ShouldRet
 }
 
 func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRequiredFieldsAreEmpty_ShouldReturnError() {
-	suite.addRemote = NewAddRemote(nil, "", "")
+	suite.addRemote = NewAddRemote(nil, "", "", suite.validation)
 
 	err := suite.addRemote.NewRemote()
 
@@ -42,7 +44,7 @@ func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRequiredFieldsAreEmpty_Sho
 func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteCreationFails_ShouldReturnError() {
 	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
-	suite.addRemote = NewAddRemote(r, "new_origin", "https://github.com/neel1996/gitconvex-test.git")
+	suite.addRemote = NewAddRemote(r, "new_origin", "https://github.com/neel1996/gitconvex-test.git", suite.validation)
 
 	err := suite.addRemote.NewRemote()
 
diff --git a/git/remote/git_remote_delete.go b/git/remote/git_remote_delete.go
index 0882a4f..d4e3b74 100644
--- a/git/remote/git_remote_delete.go
+++ b/git/remote/git_remote_delete.go
@@ -14,6 +14,7 @@ type Delete interface {
 type deleteRemote struct {
 	repo       *git2go.Repository
 	remoteName string
+	validate   Validation
 }
 
 // DeleteRemote deletes the remote based on the specified remoteName
@@ -53,9 +54,10 @@ func (d *deleteRemote) deleteSelectedRemote(remoteEntry string) error {
 	return nil
 }
 
-func NewDeleteRemote(repo *git2go.Repository, remoteName string) Delete {
+func NewDeleteRemote(repo *git2go.Repository, remoteName string, validate Validation) Delete {
 	return deleteRemote{
 		repo:       repo,
 		remoteName: remoteName,
+		validate:   validate,
 	}
 }
diff --git a/git/remote/git_remote_delete_test.go b/git/remote/git_remote_delete_test.go
index 7a24790..d2fa8f9 100644
--- a/git/remote/git_remote_delete_test.go
+++ b/git/remote/git_remote_delete_test.go
@@ -11,6 +11,7 @@ import (
 type RemoteDeleteTestSuite struct {
 	suite.Suite
 	deleteRemote Delete
+	validation   Validation
 }
 
 func TestRemoteDeleteTestSuite(t *testing.T) {
@@ -22,7 +23,8 @@ func (suite *RemoteDeleteTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.deleteRemote = NewDeleteRemote(r, "new_origin")
+	suite.validation = NewRemoteValidation()
+	suite.deleteRemote = NewDeleteRemote(r, "new_origin", suite.validation)
 }
 
 func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenNewRemoteIsDeleted_ShouldReturnNoError() {
@@ -32,7 +34,7 @@ func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenNewRemoteIsDeleted_S
 }
 
 func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRequiredFieldsAreEmpty_ShouldReturnError() {
-	suite.deleteRemote = NewDeleteRemote(nil, "")
+	suite.deleteRemote = NewDeleteRemote(nil, "", suite.validation)
 
 	err := suite.deleteRemote.DeleteRemote()
 
@@ -42,7 +44,7 @@ func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRequiredFieldsAreEmp
 func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteDeletionFails_ShouldReturnError() {
 	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
-	suite.deleteRemote = NewDeleteRemote(r, "new_origin")
+	suite.deleteRemote = NewDeleteRemote(r, "new_origin", suite.validation)
 
 	err := suite.deleteRemote.DeleteRemote()
 
diff --git a/git/remote/git_remote_list.go b/git/remote/git_remote_list.go
index 35b9bc6..8892bf2 100644
--- a/git/remote/git_remote_list.go
+++ b/git/remote/git_remote_list.go
@@ -1,7 +1,6 @@
 package remote
 
 import (
-	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
@@ -13,14 +12,16 @@ type List interface {
 }
 
 type listRemotes struct {
-	repo *git2go.Repository
+	repo     *git2go.Repository
+	validate Validation
 }
 
 func (l listRemotes) GetAllRemotes() []*model.RemoteDetails {
 	var remoteList []*model.RemoteDetails
 	repo := l.repo
 
-	if validationErr := l.validateRepo(repo); validationErr != nil {
+	if validationErr := l.validate.ValidateRemoteFields(repo); validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
 		return nil
 	}
 
@@ -54,19 +55,6 @@ func (l listRemotes) GetAllRemotes() []*model.RemoteDetails {
 	return remoteList
 }
 
-func (l listRemotes) validateRepo(repo *git2go.Repository) error {
-	if repo == nil {
-		logger.Log("Repo is nil", global.StatusError)
-		return errors.New("repo is nil")
-	}
-
-	if repo.Remotes == (git2go.RemoteCollection{}) {
-		logger.Log("Remote collection is nil", global.StatusError)
-		return errors.New("repo remote collection is nil")
-	}
-	return nil
-}
-
-func NewRemoteList(repo *git2go.Repository) List {
-	return listRemotes{repo: repo}
+func NewRemoteList(repo *git2go.Repository, validation Validation) List {
+	return listRemotes{repo: repo, validate: validation}
 }
diff --git a/git/remote/git_remote_list_test.go b/git/remote/git_remote_list_test.go
index 2ff1903..2045180 100644
--- a/git/remote/git_remote_list_test.go
+++ b/git/remote/git_remote_list_test.go
@@ -11,11 +11,13 @@ import (
 type ListRemoteTestSuite struct {
 	suite.Suite
 	listRemote List
+	validate   Validation
 }
 
 func (suite *ListRemoteTestSuite) SetupTest() {
 	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	suite.listRemote = NewRemoteList(r)
+	suite.validate = NewRemoteValidation()
+	suite.listRemote = NewRemoteList(r, suite.validate)
 }
 
 func TestListRemoteTestSuite(t *testing.T) {
@@ -36,7 +38,7 @@ func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsValid_ShouldReturn
 }
 
 func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsNil_ShouldReturnNil() {
-	suite.listRemote = NewRemoteList(nil)
+	suite.listRemote = NewRemoteList(nil, suite.validate)
 
 	remoteList := suite.listRemote.GetAllRemotes()
 
@@ -48,7 +50,7 @@ func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoHasNoRemotes_ShouldR
 		Remotes: git2go.RemoteCollection{},
 	}
 
-	suite.listRemote = NewRemoteList(r)
+	suite.listRemote = NewRemoteList(r, suite.validate)
 
 	remoteList := suite.listRemote.GetAllRemotes()
 
diff --git a/git/remote/git_remote_remote_name.go b/git/remote/git_remote_remote_name.go
index 4eb8a49..36ef2b2 100644
--- a/git/remote/git_remote_remote_name.go
+++ b/git/remote/git_remote_remote_name.go
@@ -13,13 +13,14 @@ type Name interface {
 type remoteName struct {
 	repo      *git2go.Repository
 	remoteUrl string
+	validate  Validation
 }
 
 func (r remoteName) GetRemoteNameWithUrl() string {
 	repo := r.repo
 
-	if repo == nil {
-		logger.Log("Repo is nil", global.StatusError)
+	if validationErr := r.validate.ValidateRemoteFields(repo); validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
 		return ""
 	}
 
@@ -54,9 +55,10 @@ func (r remoteName) isRemoteAvailable(remoteEntry *git2go.Remote, remote string)
 	return false
 }
 
-func NewGetRemoteName(repo *git2go.Repository, remoteUrl string) Name {
+func NewGetRemoteName(repo *git2go.Repository, remoteUrl string, validate Validation) Name {
 	return remoteName{
 		repo:      repo,
 		remoteUrl: remoteUrl,
+		validate:  validate,
 	}
 }
diff --git a/git/remote/git_remote_remote_name_test.go b/git/remote/git_remote_remote_name_test.go
index b63ed0c..1e423c1 100644
--- a/git/remote/git_remote_remote_name_test.go
+++ b/git/remote/git_remote_remote_name_test.go
@@ -12,6 +12,7 @@ type GetRemoteNameTestSuite struct {
 	suite.Suite
 	getRemoteName Name
 	repo          *git2go.Repository
+	validation    Validation
 }
 
 func (suite *GetRemoteNameTestSuite) SetupTest() {
@@ -19,7 +20,8 @@ func (suite *GetRemoteNameTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.getRemoteName = NewGetRemoteName(r, "https://github.com/neel1996/gitconvex-test.git")
+	suite.validation = NewRemoteValidation()
+	suite.getRemoteName = NewGetRemoteName(r, "https://github.com/neel1996/gitconvex-test.git", suite.validation)
 }
 
 func TestGetRemoteNameTestSuite(t *testing.T) {
@@ -36,7 +38,7 @@ func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnRemoteName_Wh
 
 func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_WhenRepoIsNil() {
 	expectedRemote := ""
-	getRemoteName := NewGetRemoteName(nil, "https://github.com/neel1996/gitconvex-test.git")
+	getRemoteName := NewGetRemoteName(nil, "https://github.com/neel1996/gitconvex-test.git", suite.validation)
 
 	actualRemote := getRemoteName.GetRemoteNameWithUrl()
 
diff --git a/git/remote/git_remote_url_data.go b/git/remote/git_remote_url_data.go
index 5411687..4364631 100644
--- a/git/remote/git_remote_url_data.go
+++ b/git/remote/git_remote_url_data.go
@@ -1,7 +1,6 @@
 package remote
 
 import (
-	"errors"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
 )
@@ -11,7 +10,8 @@ type ListRemoteUrl interface {
 }
 
 type listRemoteUrl struct {
-	repo *git2go.Repository
+	repo       *git2go.Repository
+	validation Validation
 }
 
 func (u listRemoteUrl) GetAllRemoteUrl() []*string {
@@ -19,7 +19,7 @@ func (u listRemoteUrl) GetAllRemoteUrl() []*string {
 
 	repo := u.repo
 
-	if validationErr := u.validateFields(repo); validationErr != nil {
+	if validationErr := u.validation.ValidateRemoteFields(repo); validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return nil
 	}
@@ -46,19 +46,6 @@ func (u listRemoteUrl) GetAllRemoteUrl() []*string {
 	return remoteURL
 }
 
-func (u listRemoteUrl) validateFields(repo *git2go.Repository) error {
-	if repo == nil {
-		return errors.New("repo is nil")
-	}
-
-	remoteCollection := repo.Remotes
-	if remoteCollection == (git2go.RemoteCollection{}) {
-		return errors.New("remote collection is empty")
-	}
-
-	return nil
-}
-
-func NewRemoteUrlData(repo *git2go.Repository) ListRemoteUrl {
-	return listRemoteUrl{repo: repo}
+func NewRemoteUrlData(repo *git2go.Repository, validation Validation) ListRemoteUrl {
+	return listRemoteUrl{repo: repo, validation: validation}
 }
diff --git a/git/remote/git_remote_url_data_test.go b/git/remote/git_remote_url_data_test.go
index 507d039..d38b1e9 100644
--- a/git/remote/git_remote_url_data_test.go
+++ b/git/remote/git_remote_url_data_test.go
@@ -10,6 +10,7 @@ import (
 type RemoteUrlDataTestSuite struct {
 	suite.Suite
 	listRemoteUrl ListRemoteUrl
+	validation    Validation
 }
 
 func TestRemoteUrlDataTestSuite(t *testing.T) {
@@ -18,7 +19,8 @@ func TestRemoteUrlDataTestSuite(t *testing.T) {
 
 func (suite *RemoteUrlDataTestSuite) SetupTest() {
 	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	suite.listRemoteUrl = NewRemoteUrlData(r)
+	suite.validation = NewRemoteValidation()
+	suite.listRemoteUrl = NewRemoteUrlData(r, suite.validation)
 }
 
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesArePresent_ShouldReturnRemoteUrlList() {
@@ -29,7 +31,7 @@ func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesArePresent_S
 }
 
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoIsNil_ShouldReturnNil() {
-	suite.listRemoteUrl = NewRemoteUrlData(nil)
+	suite.listRemoteUrl = NewRemoteUrlData(nil, suite.validation)
 
 	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
 
@@ -37,9 +39,12 @@ func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoIsNil_ShouldRet
 }
 
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesAreNil_ShouldReturnNil() {
-	suite.listRemoteUrl = NewRemoteUrlData(&git2go.Repository{
-		Remotes: git2go.RemoteCollection{},
-	})
+	suite.listRemoteUrl = NewRemoteUrlData(
+		&git2go.Repository{
+			Remotes: git2go.RemoteCollection{},
+		},
+		suite.validation,
+	)
 
 	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
 
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index 45f5f31..054a9e2 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -7,6 +7,7 @@ import (
 	"context"
 	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/neel1996/gitconvex/git/remote"
+	"github.com/neel1996/gitconvex/init"
 
 	"github.com/neel1996/gitconvex/api"
 	"github.com/neel1996/gitconvex/git"
@@ -113,16 +114,15 @@ func (r *mutationResolver) FetchFromRemote(ctx context.Context, repoID string, r
 		}, nil
 	}
 
-	var remoteDataObject git.RemoteDataInterface
-	remoteDataObject = git.RemoteDataStruct{
-		Repo:      repo.GitRepo,
-		RemoteURL: *remoteURL,
-	}
+	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
+	context.WithValue(ctx, initialize.RemoteUrl, remoteURL)
+
+	remoteName := initialize.RemoteObjects(ctx).RemoteName
 
 	var fetchObject git.FetchInterface
 	fetchObject = git.FetchStruct{
 		Repo:         repo.GitRepo,
-		RemoteName:   remoteDataObject.GetRemoteName(),
+		RemoteName:   remoteName.GetRemoteNameWithUrl(),
 		RepoPath:     repo.RepoPath,
 		RemoteURL:    *remoteURL,
 		RemoteBranch: *remoteBranch,
@@ -273,13 +273,8 @@ func (r *mutationResolver) PushToRemote(ctx context.Context, repoID string, remo
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
 
-	var remoteDataObject git.RemoteDataInterface
-	remoteDataObject = git.RemoteDataStruct{
-		Repo:      repo.GitRepo,
-		RemoteURL: remoteHost,
-	}
-
-	remoteName := remoteDataObject.GetRemoteName()
+	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
+	remoteName := initialize.RemoteObjects(ctx).RemoteName.GetRemoteNameWithUrl()
 
 	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil || remoteName == "" {
 		logger.Log("Repo is invalid or HEAD is nil", global.StatusError)
@@ -334,7 +329,11 @@ func (r *mutationResolver) AddRemote(ctx context.Context, repoID string, remoteN
 		return &model.RemoteMutationResult{Status: global.RemoteAddError}, nil
 	}
 
-	addRemote := remote.NewAddRemote(repo.GitRepo, remoteName, remoteURL)
+	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
+	context.WithValue(ctx, initialize.RemoteName, remoteName)
+	context.WithValue(ctx, initialize.RemoteUrl, remoteURL)
+
+	addRemote := initialize.RemoteObjects(ctx).AddRemote
 	remoteObject := remote.Operation{Add: addRemote}
 
 	return remoteObject.GitAddRemote()
@@ -353,7 +352,11 @@ func (r *mutationResolver) DeleteRemote(ctx context.Context, repoID string, remo
 		return &model.RemoteMutationResult{Status: global.RemoteAddError}, nil
 	}
 
-	deleteRemote := remote.NewDeleteRemote(repo.GitRepo, remoteName)
+	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
+	context.WithValue(ctx, initialize.RemoteName, remoteName)
+
+	deleteRemote := initialize.RemoteObjects(ctx).DeleteRemote
+
 	remoteObject := remote.Operation{
 		Delete: deleteRemote,
 	}
@@ -375,13 +378,15 @@ func (r *mutationResolver) EditRemote(ctx context.Context, repoID string, remote
 		return &model.RemoteMutationResult{Status: global.RemoteEditError}, nil
 	}
 
-	var editRemoteObject git.RemoteEditInterface
-	editRemoteObject = git.RemoteEditStruct{
-		Repo:       repo.GitRepo,
-		RemoteName: remoteName,
-		RemoteUrl:  remoteURL,
+	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
+	context.WithValue(ctx, initialize.RemoteName, remoteName)
+
+	editRemote := initialize.RemoteObjects(ctx).EditRemote
+	editRemoteObject := remote.Operation{
+		Edit: editRemote,
 	}
-	return editRemoteObject.EditRemoteUrl(), nil
+
+	return editRemoteObject.GitEditRemote()
 }
 
 func (r *queryResolver) HealthCheck(ctx context.Context) (*model.HealthCheckParams, error) {
@@ -573,12 +578,10 @@ func (r *queryResolver) GitUnPushedCommits(ctx context.Context, repoID string, r
 		logger.Log("Repo is invalid or HEAD is nil", global.StatusError)
 		return nil, nil
 	}
-	var remoteDataObject git.RemoteDataInterface
-	remoteDataObject = git.RemoteDataStruct{
-		Repo:      repo.GitRepo,
-		RemoteURL: remoteURL,
-	}
-	remoteName := remoteDataObject.GetRemoteName()
+
+	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
+	remoteName := initialize.RemoteObjects(ctx).RemoteName.GetRemoteNameWithUrl()
+
 	remoteRef := remoteName + "/" + remoteBranch
 
 	var unPushedObject git.UnPushedCommitInterface
@@ -690,12 +693,12 @@ func (r *queryResolver) GetRemote(ctx context.Context, repoID string) ([]*model.
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
 
-	var remoteObject git.RemoteDataInterface
-	remoteObject = git.RemoteDataStruct{
-		Repo: repo.GitRepo,
-	}
-	allRemoteData := remoteObject.GetAllRemotes()
-	return allRemoteData, nil
+	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
+
+	listRemote := initialize.RemoteObjects(ctx).ListRemote
+	remoteUrlList := remote.Operation{List: listRemote}
+
+	return remoteUrlList.GitGetAllRemote()
 }
 
 // Mutation returns generated.MutationResolver implementation.
@@ -707,10 +710,4 @@ func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
 type mutationResolver struct{ *Resolver }
 type queryResolver struct{ *Resolver }
 
-// !!! WARNING !!!
-// The code below was going to be deleted when updating resolvers. It has been copied here so you have
-// one last chance to move it out of harms way if you want. There are two reasons this happens:
-//  - When renaming or deleting a resolver the old code will be put in here. You can safely delete
-//    it when you're done.
-//  - You have helper methods in this file. Move them out to keep these resolver files clean.
 var logger global.Logger
diff --git a/init/init_remote.go b/init/init_remote.go
new file mode 100644
index 0000000..1f6ce0b
--- /dev/null
+++ b/init/init_remote.go
@@ -0,0 +1,46 @@
+package initialize
+
+import (
+	"context"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/remote"
+)
+
+const (
+	Repo       = "GIT_REPO"
+	RemoteName = "REMOTE_NAME"
+	RemoteUrl  = "REMOTE_URL"
+)
+
+type Remote struct {
+	AddRemote     remote.Add
+	DeleteRemote  remote.Delete
+	EditRemote    remote.Edit
+	ListRemote    remote.List
+	RemoteName    remote.Name
+	ListRemoteUrl remote.ListRemoteUrl
+}
+
+func RemoteObjects(ctx context.Context) Remote {
+	repo := ctx.Value(Repo).(*git2go.Repository)
+	remoteName := ctx.Value(RemoteName).(string)
+	remoteUrl := ctx.Value(RemoteUrl).(string)
+
+	remoteValidation := remote.NewRemoteValidation()
+
+	addRemote := remote.NewAddRemote(repo, remoteName, remoteUrl, remoteValidation)
+	deleteRemote := remote.NewDeleteRemote(repo, remoteName, remoteValidation)
+	editRemote := remote.NewEditRemote(repo, remoteName, remoteUrl, remoteValidation)
+	listRemote := remote.NewRemoteList(repo, remoteValidation)
+	name := remote.NewGetRemoteName(repo, remoteUrl, remoteValidation)
+	listRemoteURL := remote.NewRemoteUrlData(repo, remoteValidation)
+
+	return Remote{
+		AddRemote:     addRemote,
+		DeleteRemote:  deleteRemote,
+		EditRemote:    editRemote,
+		ListRemote:    listRemote,
+		ListRemoteUrl: listRemoteURL,
+		RemoteName:    name,
+	}
+}
diff --git a/tests/git_remote_allremotedata_test.go b/tests/git_remote_allremotedata_test.go
deleted file mode 100644
index 7f23fad..0000000
--- a/tests/git_remote_allremotedata_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	assert2 "github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestRemoteDataStruct_GetAllRemotes(t *testing.T) {
-	type fields struct {
-		Repo      *git.Repository
-		RemoteURL string
-	}
-
-	r, _ := git.OpenRepository(TestRepo)
-
-	tests := []struct {
-		name   string
-		fields fields
-	}{
-		{name: "Test for all remote data", fields: struct {
-			Repo      *git.Repository
-			RemoteURL string
-		}{Repo: r, RemoteURL: ""}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			res := git2.RemoteDataStruct{
-				Repo:      tt.fields.Repo,
-				RemoteURL: tt.fields.RemoteURL,
-			}
-			got := res.GetAllRemotes()
-
-			assert2.NotZero(t, got)
-		})
-	}
-}
diff --git a/tests/git_remote_data_test.go b/tests/git_remote_data_test.go
deleted file mode 100644
index 47e5669..0000000
--- a/tests/git_remote_data_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	assert2 "github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestRemoteData(t *testing.T) {
-	remoteChan := make(chan git2.RemoteDataModel)
-	r, _ := git.OpenRepository(TestRepo)
-
-	type args struct {
-		repo       *git.Repository
-		remoteChan chan git2.RemoteDataModel
-	}
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git remote data test case", args: struct {
-			repo       *git.Repository
-			remoteChan chan git2.RemoteDataModel
-		}{repo: r, remoteChan: remoteChan}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			assert := assert2.New(t)
-			var testObj git2.RemoteDataInterface
-			testObj = git2.RemoteDataStruct{
-				Repo: tt.args.repo,
-			}
-			go testObj.RemoteData(tt.args.remoteChan)
-			remoteData := <-remoteChan
-
-			rHost := remoteData.RemoteHost
-			rURL := remoteData.RemoteURL
-
-			assert.Contains(*rURL[0], "github")
-			assert.Equal(*rHost, "github")
-		})
-	}
-}
diff --git a/tests/git_remote_edit_test.go b/tests/git_remote_edit_test.go
deleted file mode 100644
index 467c523..0000000
--- a/tests/git_remote_edit_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package tests
-
-import (
-	"github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestRemoteEditStruct_EditRemoteUrl(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	type fields struct {
-		Repo       *git.Repository
-		RemoteName string
-		RemoteUrl  string
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		want   string
-	}{
-		{name: "Test edit remote api", fields: struct {
-			Repo       *git.Repository
-			RemoteName string
-			RemoteUrl  string
-		}{Repo: r, RemoteName: "origin", RemoteUrl: "https://github.com/neel1996/gitconvex-test.git"}, want: global.RemoteEditSuccess},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			e := &git2.RemoteEditStruct{
-				Repo:       tt.fields.Repo,
-				RemoteName: tt.fields.RemoteName,
-				RemoteUrl:  tt.fields.RemoteUrl,
-			}
-			got := e.EditRemoteUrl()
-
-			assert.Equal(t, tt.want, got.Status)
-		})
-	}
-}

From 08d7270e06a3f491a27870b4bada0c857a8bf1f8 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 28 Jun 2021 23:33:33 +0530
Subject: [PATCH 025/148] revise branch add api with new test suite

---
 git/branch/branch.go         |  8 +++---
 git/branch/git_branch_add.go | 50 +++++++++++++++++++++++++-----------
 2 files changed, 39 insertions(+), 19 deletions(-)

diff --git a/git/branch/branch.go b/git/branch/branch.go
index 71d6d0f..6dc727f 100644
--- a/git/branch/branch.go
+++ b/git/branch/branch.go
@@ -24,13 +24,13 @@ type Operation struct {
 }
 
 func (b Operation) GitAddBranch() (string, error) {
-	addBranchResult := b.Add.AddBranch()
+	err := b.Add.AddBranch()
 
-	if addBranchResult == global.BranchAddError {
-		return "", errors.New(global.BranchAddError)
+	if err != nil {
+		return global.BranchAddError, err
 	}
 
-	return addBranchResult, nil
+	return global.BranchAddSuccess, nil
 }
 
 func (b Operation) GitCheckoutBranch() (string, error) {
diff --git a/git/branch/git_branch_add.go b/git/branch/git_branch_add.go
index ab0f839..ec39791 100644
--- a/git/branch/git_branch_add.go
+++ b/git/branch/git_branch_add.go
@@ -1,13 +1,14 @@
 package branch
 
 import (
+	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
 )
 
 type Add interface {
-	AddBranch() string
+	AddBranch() error
 }
 
 type addBranch struct {
@@ -17,44 +18,63 @@ type addBranch struct {
 	targetCommit *git2go.Commit
 }
 
-func (a addBranch) AddBranch() string {
+func (a addBranch) AddBranch() error {
 	targetCommit := a.targetCommit
 	repo := a.repo
 	branchName := a.branchName
-	head, headErr := repo.Head()
 
-	logger.Log(fmt.Sprintf("Adding new branch -> %s", branchName), global.StatusInfo)
+	err := a.validateAddBranchFields()
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return err
+	}
+
+	head, headErr := repo.Head()
 	if headErr != nil {
 		logger.Log(fmt.Sprintf("Unable to fetch HEAD -> %s", headErr.Error()), global.StatusError)
-		return global.BranchAddError
+		return headErr
 	}
 
-	targetCommit, hasValidationErr := a.validateTargetCommit(targetCommit, repo, head)
-	if hasValidationErr {
-		return global.BranchAddError
+	targetCommit, validationErr := a.validateTargetCommit(targetCommit, repo, head)
+	if validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return validationErr
 	}
 
+	logger.Log(fmt.Sprintf("Adding new branch -> %s", branchName), global.StatusInfo)
+
 	_, branchErr := repo.CreateBranch(branchName, targetCommit, false)
 	if branchErr != nil {
 		logger.Log(fmt.Sprintf("Failed to add branch - %s - %s", branchName, branchErr.Error()), global.StatusError)
-		return global.BranchAddError
+		return branchErr
 	}
 
 	logger.Log(fmt.Sprintf("Added new branch - %s to the repo", branchName), global.StatusInfo)
-	return global.BranchAddSuccess
+	return nil
+}
+
+func (a addBranch) validateAddBranchFields() error {
+	if a.repo == nil {
+		return errors.New("repo is nil")
+	}
+
+	if a.branchName == "" {
+		return errors.New("branch name is empty")
+	}
+	return nil
 }
 
-func (a addBranch) validateTargetCommit(targetCommit *git2go.Commit, repo *git2go.Repository, head *git2go.Reference) (*git2go.Commit, bool) {
+func (a addBranch) validateTargetCommit(targetCommit *git2go.Commit, repo *git2go.Repository, head *git2go.Reference) (*git2go.Commit, error) {
 	if targetCommit != nil {
-		return targetCommit, false
+		return targetCommit, nil
 	}
 
-	headCommit, _ := repo.LookupCommit(head.Target())
+	headCommit, headCommitErr := repo.LookupCommit(head.Target())
 	if headCommit == nil {
-		return nil, true
+		return nil, headCommitErr
 	}
 
-	return headCommit, false
+	return headCommit, nil
 }
 
 func NewAddBranch(repo *git2go.Repository, branchName string, remoteSwitch bool, targetCommit *git2go.Commit) Add {

From 624d42649822d1a8221eceabd1ca7f7325847d24 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 28 Jun 2021 23:34:43 +0530
Subject: [PATCH 026/148] remove dependency with legacy test suite for repo
 setup

---
 .github/workflows/go-collab.yml     |  4 +-
 .github/workflows/go.yml            |  4 +-
 build_scripts/clone_test_repo.sh    |  3 ++
 git/branch/git_branch_add_test.go   | 65 ++++++++++++++++++++++
 git/branch/git_branch_checkout.go   | 10 ++--
 tests/beforeAll_git_setup_test.go   | 83 -----------------------------
 tests/code_file_view_test.go        |  3 +-
 tests/git_branch_add_test.go        | 36 -------------
 tests/git_branch_compare_test.go    | 27 +++++++++-
 tests/git_branch_delete_test.go     |  3 +-
 tests/git_branch_list_test.go       |  5 +-
 tests/git_changed_files_test.go     |  2 +-
 tests/git_commit_changes_test.go    |  3 +-
 tests/git_commit_compare_test.go    |  3 +-
 tests/git_commit_files_test.go      |  3 +-
 tests/git_commit_log_search_test.go |  3 +-
 tests/git_commit_logs_test.go       |  3 +-
 tests/git_ls_files_test.go          |  3 +-
 tests/git_resetall_items_test.go    |  2 +-
 tests/git_total_commits_test.go     |  3 +-
 tests/git_unpushed_commits_test.go  |  3 +-
 21 files changed, 126 insertions(+), 145 deletions(-)
 create mode 100755 build_scripts/clone_test_repo.sh
 create mode 100644 git/branch/git_branch_add_test.go
 delete mode 100644 tests/beforeAll_git_setup_test.go
 delete mode 100644 tests/git_branch_add_test.go

diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index febbf4d..484a2b9 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -45,8 +45,8 @@ jobs:
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
           go generate
-          go test ./tests -count=1 -v
-          go test $(go list ./... | grep -v "tests") -count=1 -v
+          ../../build_scripts/clone_test_repo.sh
+          go test ./... -count=1 -v
 
   gitconvex-build:
     needs:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index ccd429d..9aabce4 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -45,8 +45,8 @@ jobs:
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
           go generate
-          go test ./tests -count=1 -v
-          go test $(go list ./... | grep -v "tests") -count=1 -v
+          ../../build_scripts/clone_test_repo.sh
+          go test ./... -count=1 -v
 
   gitconvex-build:
     needs:
diff --git a/build_scripts/clone_test_repo.sh b/build_scripts/clone_test_repo.sh
new file mode 100755
index 0000000..4bea7db
--- /dev/null
+++ b/build_scripts/clone_test_repo.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+git clone https://github.com/neel1996/gitconvex-test.git $GITCONVEX_TEST_REPO
\ No newline at end of file
diff --git a/git/branch/git_branch_add_test.go b/git/branch/git_branch_add_test.go
new file mode 100644
index 0000000..1d9196c
--- /dev/null
+++ b/git/branch/git_branch_add_test.go
@@ -0,0 +1,65 @@
+package branch
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type BranchAddTestSuite struct {
+	suite.Suite
+	repo      *git2go.Repository
+	branchAdd Add
+}
+
+func TestBranchAddTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchAddTestSuite))
+}
+
+func (suite *BranchAddTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = r
+	suite.branchAdd = NewAddBranch(suite.repo, "test_1", false, nil)
+}
+
+func (suite *BranchAddTestSuite) TearDownTest() {
+	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	NewDeleteBranch(r, "test_1").DeleteBranch()
+}
+
+func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchAdditionSucceeds_ShouldReturnNil() {
+	branchAddError := suite.branchAdd.AddBranch()
+
+	suite.Nil(branchAddError)
+}
+
+func (suite *BranchAddTestSuite) TestAddBranch_WhenRepoIsNil_ShouldReturnError() {
+	suite.branchAdd = NewAddBranch(nil, "", false, nil)
+	branchAddError := suite.branchAdd.AddBranch()
+
+	suite.NotNil(branchAddError)
+}
+
+func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchNameIsEmpty_ShouldReturnError() {
+	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	suite.branchAdd = NewAddBranch(r, "", false, nil)
+	branchAddError := suite.branchAdd.AddBranch()
+
+	suite.NotNil(branchAddError)
+}
+
+func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchAdditionFails_ShouldReturnError() {
+	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	suite.branchAdd = NewAddBranch(r, "test_1", false, nil)
+
+	//Adding duplicate branches
+	_ = suite.branchAdd.AddBranch()
+	branchAddError := suite.branchAdd.AddBranch()
+
+	suite.NotNil(branchAddError)
+}
diff --git a/git/branch/git_branch_checkout.go b/git/branch/git_branch_checkout.go
index e958d08..9cdd661 100644
--- a/git/branch/git_branch_checkout.go
+++ b/git/branch/git_branch_checkout.go
@@ -1,7 +1,6 @@
 package branch
 
 import (
-	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
@@ -142,11 +141,10 @@ func (b branchCheckout) checkoutLocalBranch(branchDetails validatedBranchDetails
 func addAndCheckoutNewBranch(repo *git2go.Repository, branchName string, remoteCommit *git2go.Commit, branchDetails validatedBranchDetails) error {
 	addBranch := NewAddBranch(repo, branchName, false, remoteCommit)
 
-	branchCreateStatus := addBranch.AddBranch()
-	if branchCreateStatus == global.BranchAddError {
-		err := errors.New("branch creation failed")
-		branchCheckoutError(err)
-		return err
+	branchAddError := addBranch.AddBranch()
+	if branchAddError != nil {
+		branchCheckoutError(branchAddError)
+		return branchAddError
 	}
 
 	if err := repo.SetHead(branchDetails.referenceBranchName); err != nil {
diff --git a/tests/beforeAll_git_setup_test.go b/tests/beforeAll_git_setup_test.go
deleted file mode 100644
index 848f45b..0000000
--- a/tests/beforeAll_git_setup_test.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package tests
-
-import (
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/git"
-	"github.com/sirupsen/logrus"
-	"io/ioutil"
-	"os"
-	"strconv"
-	"testing"
-)
-
-var TestRepo string
-var logger *logrus.Logger
-
-func TestMain(m *testing.M) {
-	logger = logrus.New()
-	TestRepo = os.Getenv("GITCONVEX_TEST_REPO")
-	if TestRepo == "" {
-		logger.Error("No test repo passed. Set GITCONVEX_TEST_REPO to a git directory to run integration tests")
-		os.Exit(1)
-	}
-
-	var testObject git.CloneInterface
-	testObject = git.CloneStruct{
-		RepoName:   "",
-		RepoPath:   TestRepo,
-		RepoURL:    "https://github.com/neel1996/gitconvex-test.git",
-		AuthOption: "noauth",
-		SSHKeyPath: "",
-		UserName:   "",
-		Password:   "",
-	}
-
-	cloneTestRepo(testObject)
-
-	logger.Info("Initiating integration tests")
-	m.Run()
-	tearDownTests()
-}
-
-func SetupTestRepoStageAndCommit(msg string) bool {
-	repository, repoErr := git2go.OpenRepository(TestRepo)
-	if repoErr != nil {
-		return true
-	}
-
-	initFile := "init_file.txt"
-	_ = ioutil.WriteFile(TestRepo+"/"+initFile, []byte{byte(63)}, 0755)
-
-	git.StageAllStruct{Repo: repository}.StageAllItems()
-	git.CommitStruct{
-		Repo:          repository,
-		CommitMessage: msg,
-		RepoPath:      TestRepo,
-	}.CommitChanges()
-
-	return false
-}
-
-func cloneTestRepo(testObject git.CloneInterface) {
-	_, err := testObject.CloneRepo()
-	if err != nil {
-		logger.Error("Unable to clone the test repo")
-		os.Exit(2)
-	}
-}
-
-func tearDownTests() {
-	removeFlag, _ := strconv.ParseBool(os.Getenv("GITCONVEX_DELETE_TEST_REPO"))
-	if !removeFlag {
-		logger.Error("Test repo will be retained. If you use the same test repo again then the tests will fail during cloning stage")
-		return
-	}
-
-	// Enable for deleting the test repo after running the tests
-
-	//err := os.RemoveAll(os.Getenv("GITCONVEX_TEST_REPO"))
-	//if err != nil {
-	//	logger.Error(err)
-	//	return
-	//}
-}
diff --git a/tests/code_file_view_test.go b/tests/code_file_view_test.go
index b891ba7..94b927b 100644
--- a/tests/code_file_view_test.go
+++ b/tests/code_file_view_test.go
@@ -4,11 +4,12 @@ import (
 	git "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/api"
 	"github.com/stretchr/testify/assert"
+	"os"
 	"testing"
 )
 
 func TestCodeFileView(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
 	type args struct {
 		repo     *git.Repository
diff --git a/tests/git_branch_add_test.go b/tests/git_branch_add_test.go
deleted file mode 100644
index 2cfbcd5..0000000
--- a/tests/git_branch_add_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/git/branch"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestAddBranch(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	type args struct {
-		repo       *git.Repository
-		branchName string
-	}
-	tests := []struct {
-		name string
-		args args
-		want string
-	}{
-		{name: "Git branch add test case", args: struct {
-			repo       *git.Repository
-			branchName string
-		}{repo: r, branchName: "test"}, want: "BRANCH_CREATION_SUCCESS"},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			obj := branch.NewAddBranch(tt.args.repo, tt.args.branchName, false, nil)
-			got := obj.AddBranch()
-			assert.Equal(t, tt.want, got)
-
-			_, _ = branch.Operation{Delete: branch.NewDeleteBranch(r, "test")}.GitDeleteBranch()
-		})
-	}
-}
diff --git a/tests/git_branch_compare_test.go b/tests/git_branch_compare_test.go
index ba65356..b165cf4 100644
--- a/tests/git_branch_compare_test.go
+++ b/tests/git_branch_compare_test.go
@@ -2,13 +2,16 @@ package tests
 
 import (
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git"
 	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/stretchr/testify/assert"
+	"io/ioutil"
+	"os"
 	"testing"
 )
 
 func Test_branchCompare_CompareBranch(t *testing.T) {
-	r, _ := git2go.OpenRepository(TestRepo)
+	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
 	type fields struct {
 		repo       *git2go.Repository
@@ -29,7 +32,7 @@ func Test_branchCompare_CompareBranch(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			branch.NewAddBranch(r, tt.fields.diffBranch, false, nil).AddBranch()
 			branch.NewBranchCheckout(r, tt.fields.diffBranch).CheckoutBranch()
-			SetupTestRepoStageAndCommit("Comparison commit for branch compare")
+			setupTestRepoStageAndCommit("Comparison commit for branch compare")
 
 			branch.NewBranchCheckout(r, tt.fields.baseBranch).CheckoutBranch()
 
@@ -40,3 +43,23 @@ func Test_branchCompare_CompareBranch(t *testing.T) {
 		})
 	}
 }
+
+func setupTestRepoStageAndCommit(msg string) bool {
+	testRepo := os.Getenv("GITCONVEX_TEST_REPO")
+	repository, repoErr := git2go.OpenRepository(testRepo)
+	if repoErr != nil {
+		return true
+	}
+
+	initFile := "init_file.txt"
+	_ = ioutil.WriteFile(testRepo+"/"+initFile, []byte{byte(63)}, 0755)
+
+	git.StageAllStruct{Repo: repository}.StageAllItems()
+	git.CommitStruct{
+		Repo:          repository,
+		CommitMessage: msg,
+		RepoPath:      testRepo,
+	}.CommitChanges()
+
+	return false
+}
diff --git a/tests/git_branch_delete_test.go b/tests/git_branch_delete_test.go
index de4cec7..ceefde5 100644
--- a/tests/git_branch_delete_test.go
+++ b/tests/git_branch_delete_test.go
@@ -5,11 +5,12 @@ import (
 	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/stretchr/testify/assert"
+	"os"
 	"testing"
 )
 
 func TestDeleteBranch(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
 	type args struct {
 		repo       *git.Repository
diff --git a/tests/git_branch_list_test.go b/tests/git_branch_list_test.go
index b072101..8e6017f 100644
--- a/tests/git_branch_list_test.go
+++ b/tests/git_branch_list_test.go
@@ -4,12 +4,13 @@ import (
 	"github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/stretchr/testify/assert"
+	"os"
 	"testing"
 )
 
 func TestGetBranchList(t *testing.T) {
 	b := make(chan branch.ListOfBranches)
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
 	type args struct {
 		repo       *git.Repository
@@ -27,7 +28,7 @@ func TestGetBranchList(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			testObj := branch.NewBranchListInterface(tt.args.repo)
-			
+
 			go testObj.ListBranches(tt.args.branchChan)
 			branchList := <-tt.args.branchChan
 
diff --git a/tests/git_changed_files_test.go b/tests/git_changed_files_test.go
index 0bd4e0f..c64930e 100644
--- a/tests/git_changed_files_test.go
+++ b/tests/git_changed_files_test.go
@@ -13,7 +13,7 @@ import (
 )
 
 func TestChangedFiles(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	repoPath := r.Workdir()
 
 	mockFile := "mockFile.txt"
diff --git a/tests/git_commit_changes_test.go b/tests/git_commit_changes_test.go
index 8c71949..d272484 100644
--- a/tests/git_commit_changes_test.go
+++ b/tests/git_commit_changes_test.go
@@ -6,11 +6,12 @@ import (
 	git2 "github.com/neel1996/gitconvex/git"
 	"github.com/stretchr/testify/assert"
 	"io/ioutil"
+	"os"
 	"testing"
 )
 
 func TestCommitChanges(t *testing.T) {
-	r, _ := git2go.OpenRepository(TestRepo)
+	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	repoPath := r.Workdir()
 
 	sampleFile := "untracked.txt"
diff --git a/tests/git_commit_compare_test.go b/tests/git_commit_compare_test.go
index f5162bb..b65c35a 100644
--- a/tests/git_commit_compare_test.go
+++ b/tests/git_commit_compare_test.go
@@ -4,11 +4,12 @@ import (
 	"github.com/libgit2/git2go/v31"
 	git2 "github.com/neel1996/gitconvex/git"
 	"github.com/stretchr/testify/assert"
+	"os"
 	"testing"
 )
 
 func TestCompareCommit(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
 	sampleCommits := git2.CommitLogStruct{
 		Repo:            r,
diff --git a/tests/git_commit_files_test.go b/tests/git_commit_files_test.go
index 9baddfa..f2dbf8e 100644
--- a/tests/git_commit_files_test.go
+++ b/tests/git_commit_files_test.go
@@ -4,11 +4,12 @@ import (
 	git "github.com/libgit2/git2go/v31"
 	git2 "github.com/neel1996/gitconvex/git"
 	"github.com/stretchr/testify/assert"
+	"os"
 	"testing"
 )
 
 func TestCommitFileList(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
 	sampleCommits := git2.CommitLogStruct{
 		Repo:            r,
diff --git a/tests/git_commit_log_search_test.go b/tests/git_commit_log_search_test.go
index 864d5b4..49d313a 100644
--- a/tests/git_commit_log_search_test.go
+++ b/tests/git_commit_log_search_test.go
@@ -4,11 +4,12 @@ import (
 	git "github.com/libgit2/git2go/v31"
 	git2 "github.com/neel1996/gitconvex/git"
 	"github.com/stretchr/testify/assert"
+	"os"
 	"testing"
 )
 
 func TestSearchCommitLogs(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
 	sampleCommits := git2.CommitLogStruct{
 		Repo:            r,
diff --git a/tests/git_commit_logs_test.go b/tests/git_commit_logs_test.go
index f946a43..d3ca1b2 100644
--- a/tests/git_commit_logs_test.go
+++ b/tests/git_commit_logs_test.go
@@ -4,11 +4,12 @@ import (
 	git "github.com/libgit2/git2go/v31"
 	git2 "github.com/neel1996/gitconvex/git"
 	assert2 "github.com/stretchr/testify/assert"
+	"os"
 	"testing"
 )
 
 func TestCommitLogs(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
 	type args struct {
 		repo      *git.Repository
diff --git a/tests/git_ls_files_test.go b/tests/git_ls_files_test.go
index 8d2c175..c20937f 100644
--- a/tests/git_ls_files_test.go
+++ b/tests/git_ls_files_test.go
@@ -4,12 +4,13 @@ import (
 	"github.com/libgit2/git2go/v31"
 	git2 "github.com/neel1996/gitconvex/git"
 	"github.com/stretchr/testify/assert"
+	"os"
 	"testing"
 )
 
 func TestListFiles(t *testing.T) {
 	lsFileChan := make(chan *git2.LsFileInfo)
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	repoPath := r.Workdir()
 
 	type args struct {
diff --git a/tests/git_resetall_items_test.go b/tests/git_resetall_items_test.go
index 65d6b1a..95a5ef6 100644
--- a/tests/git_resetall_items_test.go
+++ b/tests/git_resetall_items_test.go
@@ -10,7 +10,7 @@ import (
 )
 
 func TestResetAllItems(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
 	mockFile := "untracked.txt"
 	_ = ioutil.WriteFile(mockFile, []byte{byte(63)}, 0755)
diff --git a/tests/git_total_commits_test.go b/tests/git_total_commits_test.go
index 17ce7f0..df9af7a 100644
--- a/tests/git_total_commits_test.go
+++ b/tests/git_total_commits_test.go
@@ -4,11 +4,12 @@ import (
 	git "github.com/libgit2/git2go/v31"
 	git2 "github.com/neel1996/gitconvex/git"
 	"github.com/stretchr/testify/assert"
+	"os"
 	"testing"
 )
 
 func TestTotalCommitLogs(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
 	logChan := make(chan git2.AllCommitData)
 
diff --git a/tests/git_unpushed_commits_test.go b/tests/git_unpushed_commits_test.go
index 53fab02..130bc7b 100644
--- a/tests/git_unpushed_commits_test.go
+++ b/tests/git_unpushed_commits_test.go
@@ -5,11 +5,12 @@ import (
 	git2 "github.com/neel1996/gitconvex/git"
 	"github.com/stretchr/testify/assert"
 	"io/ioutil"
+	"os"
 	"testing"
 )
 
 func TestUnPushedCommits(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	repoPath := r.Workdir()
 
 	untrackedResult := "untracked.txt"

From 842e6faaaf40c0d75d54e9749a48e90de3baac67 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 29 Jun 2021 10:15:53 +0530
Subject: [PATCH 027/148] update script path with GH actions env variable

---
 .github/workflows/go-collab.yml | 2 +-
 .github/workflows/go.yml        | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index 484a2b9..f09cde1 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -45,7 +45,7 @@ jobs:
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
           go generate
-          ../../build_scripts/clone_test_repo.sh
+          $GITHUB_WORKSPACE/build_scripts/clone_test_repo.sh
           go test ./... -count=1 -v
 
   gitconvex-build:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 9aabce4..33054b5 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -45,7 +45,7 @@ jobs:
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
           go generate
-          ../../build_scripts/clone_test_repo.sh
+          $GITHUB_WORKSPACE/build_scripts/clone_test_repo.sh
           go test ./... -count=1 -v
 
   gitconvex-build:

From 1adf2df5ecc31b9f066b56c4399be291584bccf3 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 30 Jun 2021 00:19:02 +0530
Subject: [PATCH 028/148] update branch checkout with new test suite and
 validations

---
 .gitignore                             |   1 +
 Makefile                               |  13 +--
 git/branch/branch.go                   |   9 +-
 git/branch/branch_validation.go        |  36 ++++++++
 git/branch/branch_validation_test.go   |  53 +++++++++++
 git/branch/git_branch_checkout.go      | 118 ++++++++++++-------------
 git/branch/git_branch_checkout_test.go |  80 +++++++++++++++++
 global/status_strings.go               |   1 +
 8 files changed, 241 insertions(+), 70 deletions(-)
 create mode 100644 git/branch/branch_validation.go
 create mode 100644 git/branch/branch_validation_test.go
 create mode 100644 git/branch/git_branch_checkout_test.go

diff --git a/.gitignore b/.gitignore
index 8d9f721..d3115bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ build/
 database/
 ui/
 dist/
+gitconvex-test/
 
 env_config.json
 gitclient
diff --git a/Makefile b/Makefile
index 9988493..19b7b25 100644
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,7 @@ bundle:
 
 pack:
 	cd ./dist && \
-	tar -cvzf gitconvex-$(GITCONVEX_VERSION).tar.gz .
+	tar -cvzf gitconvex-$$GITCONVEX_VERSION.tar.gz .
 
 build: clean build-ui bundle build-server
 	@echo "✅ Gitconvex Build Completed successfully!"
@@ -29,10 +29,13 @@ build: clean build-ui bundle build-server
 	@echo "📬 Try ./dist/gitconvex --port PORT_NUMBER to run gitconvex on the desired port"
 
 test:
-	mkdir -p testRepo
-	export GITCONVEX_TEST_REPO=$(pwd)/testRepo && export GITCONVEX_DEFAULT_PATH=$(pwd)/testRepo
-	cd $GITCONVEX_TEST_REPO
-	go test -v ./...
+	export GITCONVEX_TEST_REPO="$(PWD)/gitconvex-test" && \
+	export GITCONVEX_DEFAULT_PATH="$(PWD)/gitconvex-test" && \
+	rm -rf $$GITCONVEX_TEST_REPO && \
+ 	go clean --cache && \
+ 	./build_scripts/clone_test_repo.sh && \
+ 	go test ./... -count=1 && \
+	rm -rf $$GITCONVEX_TEST_REPO
 
 start:
 	./dist/gitconvex
diff --git a/git/branch/branch.go b/git/branch/branch.go
index 6dc727f..d3c845d 100644
--- a/git/branch/branch.go
+++ b/git/branch/branch.go
@@ -34,13 +34,13 @@ func (b Operation) GitAddBranch() (string, error) {
 }
 
 func (b Operation) GitCheckoutBranch() (string, error) {
-	checkoutBranchResult := b.Checkout.CheckoutBranch()
+	err := b.Checkout.CheckoutBranch()
 
-	if checkoutBranchResult == global.BranchCheckoutError {
-		return "", errors.New(global.BranchCheckoutError)
+	if err != nil {
+		return global.BranchCheckoutError, err
 	}
 
-	return checkoutBranchResult, nil
+	return global.BranchCheckoutSuccess, nil
 }
 
 func (b Operation) GitCompareBranches() ([]*model.BranchCompareResults, error) {
@@ -66,3 +66,4 @@ func (b Operation) GitDeleteBranch() (*model.BranchDeleteStatus, error) {
 func (b Operation) GitListBranches(branchChannel chan ListOfBranches) {
 	b.List.ListBranches(branchChannel)
 }
+
diff --git a/git/branch/branch_validation.go b/git/branch/branch_validation.go
new file mode 100644
index 0000000..2e0f663
--- /dev/null
+++ b/git/branch/branch_validation.go
@@ -0,0 +1,36 @@
+package branch
+
+import (
+	"errors"
+	git2go "github.com/libgit2/git2go/v31"
+)
+
+type Validation interface {
+	ValidateBranchFields() error
+}
+
+type validateBranch struct {
+	repo       *git2go.Repository
+	branchName string
+}
+
+func (v validateBranch) ValidateBranchFields() error {
+	if v.repo == nil {
+		err := "repo is nil"
+		return errors.New(err)
+	}
+
+	if v.branchName == "" {
+		err := "branch name is empty"
+		return errors.New(err)
+	}
+
+	return nil
+}
+
+func NewBranchFieldsValidation(repo *git2go.Repository, branchName string) Validation {
+	return validateBranch{
+		repo:       repo,
+		branchName: branchName,
+	}
+}
diff --git a/git/branch/branch_validation_test.go b/git/branch/branch_validation_test.go
new file mode 100644
index 0000000..42f467a
--- /dev/null
+++ b/git/branch/branch_validation_test.go
@@ -0,0 +1,53 @@
+package branch
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type BranchFieldValidationTestSuite struct {
+	suite.Suite
+	repo       *git2go.Repository
+	branchName string
+	validation Validation
+}
+
+func TestBranchFieldValidationTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchFieldValidationTestSuite))
+}
+
+func (suite *BranchFieldValidationTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = r
+	suite.branchName = "test_branch"
+	suite.validation = NewBranchFieldsValidation(suite.repo, suite.branchName)
+}
+
+func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenAllFieldsAreValid_ShouldReturnNil() {
+	err := suite.validation.ValidateBranchFields()
+
+	suite.Nil(err)
+}
+
+func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenRepoIsNil_ShouldReturnError() {
+	suite.validation = NewBranchFieldsValidation(nil, "test_branch")
+	err := suite.validation.ValidateBranchFields()
+
+	suite.NotNil(err)
+	suite.Equal("repo is nil", err.Error())
+}
+
+func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenBranchNameIsEmpty_ShouldReturnError() {
+	suite.validation = NewBranchFieldsValidation(suite.repo, "")
+	err := suite.validation.ValidateBranchFields()
+
+	suite.NotNil(err)
+	suite.Equal("branch name is empty", err.Error())
+}
diff --git a/git/branch/git_branch_checkout.go b/git/branch/git_branch_checkout.go
index 9cdd661..6a42237 100644
--- a/git/branch/git_branch_checkout.go
+++ b/git/branch/git_branch_checkout.go
@@ -8,7 +8,7 @@ import (
 )
 
 type Checkout interface {
-	CheckoutBranch() string
+	CheckoutBranch() error
 }
 
 type branchCheckout struct {
@@ -23,102 +23,99 @@ type validatedBranchDetails struct {
 	isRemoteBranch      bool
 }
 
-func branchCheckoutError(err error) string {
+func printAndReturnError(err error) error {
 	logger.Log(err.Error(), global.StatusError)
-	return global.BranchCheckoutError
+	return err
 }
 
-func checkErrorAndPanic(err error) bool {
+// CheckoutBranch checks out the branchName received as argument
+func (b branchCheckout) CheckoutBranch() error {
+	err := b.validateBranchFields()
 	if err != nil {
-		logger.Log(err.Error(), global.StatusError)
-		panic(err)
-		return true
+		return err
 	}
-	return false
-}
-
-// CheckoutBranch checks out the branchName received as argument
-func (b branchCheckout) CheckoutBranch() string {
-	var errStatus bool
-	branchName := b.branchName
 
-	defer func() string {
-		if r := recover(); r != nil {
-			logger.Log(fmt.Sprintf("%v", r), global.StatusError)
-			return global.BranchCheckoutError
-		}
-		return global.BranchCheckoutError
-	}()
-
-	branchDetails := b.validateAndSetBranchDetails(branchName)
+	branchDetails := b.validateAndSetBranchDetails()
 
 	if branchDetails.isRemoteBranch {
-		errStatus = b.checkoutRemoteBranch(branchDetails)
+		return b.checkoutRemoteBranch(branchDetails)
 	}
 
-	errStatus = b.checkoutLocalBranch(branchDetails)
+	return b.checkoutLocalBranch(branchDetails)
+}
 
-	if errStatus {
-		return global.BranchCheckoutError
-	} else {
-		logger.Log(fmt.Sprintf("Current branch checked out to -> %s", branchName), global.StatusInfo)
-		return fmt.Sprintf("Head checked out to branch - %v", branchName)
+func (b branchCheckout) validateBranchFields() error {
+	validation := NewBranchFieldsValidation(b.repo, b.branchName)
+	err := validation.ValidateBranchFields()
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return err
 	}
+	return nil
 }
 
-func (b branchCheckout) checkoutRemoteBranch(branchDetails validatedBranchDetails) bool {
-	var errStatus bool
+func (b branchCheckout) checkoutRemoteBranch(branchDetails validatedBranchDetails) error {
 	branchName := b.branchName
 	repo := b.repo
 
 	logger.Log(fmt.Sprintf("Branch - %s is a remote branch. Trying with intermediate remote fetch!", branchName), global.StatusWarning)
 
 	remoteBranch, remoteBranchErr := repo.LookupBranch(branchDetails.remoteBranchName, git2go.BranchRemote)
-	errStatus = checkErrorAndPanic(remoteBranchErr)
+	if remoteBranchErr != nil {
+		return printAndReturnError(remoteBranchErr)
+	}
 
 	remoteHead := remoteBranch.Target()
-
 	remoteCommit, remoteCommitErr := repo.LookupCommit(remoteHead)
-	errStatus = checkErrorAndPanic(remoteCommitErr)
+	if remoteCommitErr != nil {
+		return printAndReturnError(remoteCommitErr)
+
+	}
 
 	remoteTree, remoteTreeErr := remoteCommit.Tree()
-	errStatus = checkErrorAndPanic(remoteTreeErr)
+	if remoteTreeErr != nil {
+		return printAndReturnError(remoteTreeErr)
+	}
 
-	checkoutErr := repo.CheckoutTree(remoteTree, &git2go.CheckoutOptions{Strategy: git2go.CheckoutSafe})
-	errStatus = checkErrorAndPanic(checkoutErr)
+	if checkoutErr := repo.CheckoutTree(remoteTree, &git2go.CheckoutOptions{Strategy: git2go.CheckoutSafe}); checkoutErr != nil {
+		return printAndReturnError(checkoutErr)
+	}
 
 	_, localLookupErr := repo.LookupBranch(branchName, git2go.BranchLocal)
 	if localLookupErr != nil {
 		logger.Log(localLookupErr.Error(), global.StatusError)
-		if err := addAndCheckoutNewBranch(repo, branchName, remoteCommit, branchDetails); err != nil {
-			return true
-		}
-		return errStatus
+		return addAndCheckoutNewBranch(repo, branchName, remoteCommit, branchDetails)
 	}
 
 	if err := repo.SetHead(branchDetails.referenceBranchName); err != nil {
-		branchCheckoutError(err)
-		return errStatus
+		return printAndReturnError(err)
 	}
 
-	return errStatus
+	logger.Log(fmt.Sprintf("Remote branch %v has been checked out", branchDetails.remoteBranchName), global.StatusInfo)
+	return nil
 }
 
-func (b branchCheckout) checkoutLocalBranch(branchDetails validatedBranchDetails) bool {
-	errStatus := false
+func (b branchCheckout) checkoutLocalBranch(branchDetails validatedBranchDetails) error {
 	repo := b.repo
 	branchName := b.branchName
 
 	branch, branchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
-	errStatus = checkErrorAndPanic(branchErr)
+	if branchErr != nil {
+		fmt.Println("Lookup error")
+		return printAndReturnError(branchErr)
+	}
 
-	topCommit, _ := repo.LookupCommit(branch.Target())
-	if topCommit == nil {
-		return true
+	lookupCommit, lookupCommitErr := repo.LookupCommit(branch.Target())
+	if lookupCommit == nil {
+		fmt.Println("Lookup commit error")
+		return printAndReturnError(lookupCommitErr)
 	}
 
-	tree, treeErr := topCommit.Tree()
-	errStatus = checkErrorAndPanic(treeErr)
+	tree, treeErr := lookupCommit.Tree()
+	if treeErr != nil {
+		fmt.Println("Lookup tree error")
+		return printAndReturnError(treeErr)
+	}
 
 	checkoutErr := repo.CheckoutTree(tree, &git2go.CheckoutOptions{
 		Strategy:       git2go.CheckoutSafe,
@@ -126,16 +123,16 @@ func (b branchCheckout) checkoutLocalBranch(branchDetails validatedBranchDetails
 	})
 
 	if checkoutErr != nil {
-		branchCheckoutError(checkoutErr)
-		return true
+		return printAndReturnError(checkoutErr)
 	}
 
 	err := repo.SetHead(branchDetails.referenceBranchName)
 	if err != nil {
-		branchCheckoutError(err)
-		return true
+		return printAndReturnError(err)
 	}
-	return errStatus
+
+	logger.Log(fmt.Sprintf("Local branch %v has been checked out", b.branchName), global.StatusInfo)
+	return nil
 }
 
 func addAndCheckoutNewBranch(repo *git2go.Repository, branchName string, remoteCommit *git2go.Commit, branchDetails validatedBranchDetails) error {
@@ -143,20 +140,19 @@ func addAndCheckoutNewBranch(repo *git2go.Repository, branchName string, remoteC
 
 	branchAddError := addBranch.AddBranch()
 	if branchAddError != nil {
-		branchCheckoutError(branchAddError)
 		return branchAddError
 	}
 
 	if err := repo.SetHead(branchDetails.referenceBranchName); err != nil {
-		branchCheckoutError(err)
 		return err
 	}
 
 	return nil
 }
 
-func (b branchCheckout) validateAndSetBranchDetails(branchName string) validatedBranchDetails {
+func (b branchCheckout) validateAndSetBranchDetails() validatedBranchDetails {
 	var (
+		branchName          = b.branchName
 		referenceBranchName string
 		remoteBranchName    string
 		isRemoteBranch      bool
diff --git a/git/branch/git_branch_checkout_test.go b/git/branch/git_branch_checkout_test.go
new file mode 100644
index 0000000..bc95b0e
--- /dev/null
+++ b/git/branch/git_branch_checkout_test.go
@@ -0,0 +1,80 @@
+package branch
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type BranchCheckoutTestSuite struct {
+	suite.Suite
+	branchName     string
+	checkoutBranch Checkout
+	repo           *git2go.Repository
+}
+
+func TestBranchCheckoutTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchCheckoutTestSuite))
+}
+
+func (suite *BranchCheckoutTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.branchName = "test_checkout"
+	addErr := NewAddBranch(r, suite.branchName, false, nil).AddBranch()
+	if addErr != nil {
+		fmt.Println(addErr)
+	}
+	suite.repo = r
+	suite.checkoutBranch = NewBranchCheckout(suite.repo, suite.branchName)
+}
+
+func (suite *BranchCheckoutTestSuite) TearDownSuite() {
+	suite.branchName = "master"
+	err := suite.checkoutBranch.CheckoutBranch()
+	if err != nil {
+		return
+	}
+	NewDeleteBranch(suite.repo, suite.branchName).DeleteBranch()
+}
+
+func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenBranchIsCheckedOut_ShouldReturnNil() {
+	err := suite.checkoutBranch.CheckoutBranch()
+
+	suite.Nil(err)
+}
+
+func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenRemoteBranchIsCheckedOut_ShouldReturnNil() {
+	suite.checkoutBranch = NewBranchCheckout(suite.repo, "remotes/origin/master")
+	err := suite.checkoutBranch.CheckoutBranch()
+
+	suite.Nil(err)
+}
+
+func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenRepoIsNil_ShouldReturnError() {
+	suite.checkoutBranch = NewBranchCheckout(nil, "test_branch")
+	err := suite.checkoutBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+	suite.Equal("repo is nil", err.Error())
+}
+
+func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenBranchNameIsEmpty_ShouldReturnError() {
+	suite.checkoutBranch = NewBranchCheckout(suite.repo, "")
+	err := suite.checkoutBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+	suite.Equal("branch name is empty", err.Error())
+}
+
+func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenNonExistingBranchIsSelected_ShouldReturnError() {
+	suite.checkoutBranch = NewBranchCheckout(suite.repo, "no_exists")
+	err := suite.checkoutBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
diff --git a/global/status_strings.go b/global/status_strings.go
index f1eb09a..aeee579 100644
--- a/global/status_strings.go
+++ b/global/status_strings.go
@@ -2,6 +2,7 @@ package global
 
 const (
 	BranchAddSuccess       = "BRANCH_CREATION_SUCCESS"
+	BranchCheckoutSuccess  = "BRANCH_CHECKOUT_SUCCESS"
 	BranchDeleteSuccess    = "BRANCH_DELETE_SUCCESS"
 	RemoteAddSuccess       = "REMOTE_ADD_SUCCESS"
 	RemoteDeleteSuccess    = "REMOTE_DELETE_SUCCESS"

From c858ae6cbbb215fb470f595724a642f07547f507 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 30 Jun 2021 23:52:54 +0530
Subject: [PATCH 029/148] remove remote validation as a struct dependency and
 make in-package calls for validations

---
 api/repo_status.go                        |  5 ++---
 git/remote/git_remote_add.go              |  6 ++----
 git/remote/git_remote_add_test.go         | 10 ++++------
 git/remote/git_remote_delete.go           |  6 ++----
 git/remote/git_remote_delete_test.go      |  8 +++-----
 git/remote/git_remote_edit.go             |  6 ++----
 git/remote/git_remote_edit_test.go        |  9 ++++-----
 git/remote/git_remote_list.go             |  9 ++++-----
 git/remote/git_remote_list_test.go        |  8 +++-----
 git/remote/git_remote_remote_name.go      |  6 ++----
 git/remote/git_remote_remote_name_test.go |  6 ++----
 git/remote/git_remote_url_data.go         |  9 ++++-----
 git/remote/git_remote_url_data_test.go    | 15 +++++----------
 git/remote/remote_validation.go           | 12 ++++++------
 git/remote/remote_validation_test.go      | 10 ++++++----
 init/init_remote.go                       | 14 ++++++--------
 16 files changed, 57 insertions(+), 82 deletions(-)

diff --git a/api/repo_status.go b/api/repo_status.go
index 2e94a73..0149410 100644
--- a/api/repo_status.go
+++ b/api/repo_status.go
@@ -48,8 +48,7 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	)
 	remoteURL = &tempRemote
 
-	remoteValidation := remote.NewRemoteValidation()
-	remoteUrlList := remote.NewRemoteUrlData(repo, remoteValidation)
+	remoteUrlList := remote.NewRemoteUrlData(repo)
 	listRemoteUrl := remote.Operation{ListRemoteUrl: remoteUrlList}
 
 	remotes, remoteErr := listRemoteUrl.GitGetAllRemoteUrl()
@@ -59,7 +58,7 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	}
 
 	if len(remotes) > 0 && *remotes[0] != "" {
-		remoteNameObject := remote.NewGetRemoteName(repo, *remotes[0], remoteValidation)
+		remoteNameObject := remote.NewGetRemoteName(repo, *remotes[0])
 		remoteName = remoteNameObject.GetRemoteNameWithUrl()
 		sRemote := strings.Split(*remotes[0], "/")
 		repoName = &sRemote[len(sRemote)-1]
diff --git a/git/remote/git_remote_add.go b/git/remote/git_remote_add.go
index 11ff850..365333e 100644
--- a/git/remote/git_remote_add.go
+++ b/git/remote/git_remote_add.go
@@ -15,7 +15,6 @@ type addRemote struct {
 	repo       *git2go.Repository
 	remoteName string
 	remoteURL  string
-	validate   Validation
 }
 
 // NewRemote adds a new remote to the target git repo
@@ -36,7 +35,7 @@ func (a addRemote) NewRemote() error {
 }
 
 func (a addRemote) validateRemoteFields() error {
-	validationErr := a.validate.ValidateRemoteFields(a.repo)
+	validationErr := NewRemoteValidation(a.repo).ValidateRemoteFields()
 	if validationErr != nil {
 		return validationErr
 	}
@@ -48,11 +47,10 @@ func (a addRemote) validateRemoteFields() error {
 	return nil
 }
 
-func NewAddRemote(repo *git2go.Repository, remoteName string, remoteURL string, validate Validation) Add {
+func NewAddRemote(repo *git2go.Repository, remoteName string, remoteURL string) Add {
 	return addRemote{
 		repo:       repo,
 		remoteName: remoteName,
 		remoteURL:  remoteURL,
-		validate:   validate,
 	}
 }
diff --git a/git/remote/git_remote_add_test.go b/git/remote/git_remote_add_test.go
index 67c69ff..6d5ec17 100644
--- a/git/remote/git_remote_add_test.go
+++ b/git/remote/git_remote_add_test.go
@@ -10,8 +10,7 @@ import (
 
 type RemoteAddTestSuite struct {
 	suite.Suite
-	addRemote  Add
-	validation Validation
+	addRemote Add
 }
 
 func TestRemoteAddTestSuite(t *testing.T) {
@@ -23,8 +22,7 @@ func (suite *RemoteAddTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.validation = NewRemoteValidation()
-	suite.addRemote = NewAddRemote(r, "new_origin", "https://github.com/neel1996/gitconvex-test.git", suite.validation)
+	suite.addRemote = NewAddRemote(r, "new_origin", "https://github.com/neel1996/gitconvex-test.git")
 }
 
 func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenNewRemoteIsAdded_ShouldReturnNoError() {
@@ -34,7 +32,7 @@ func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenNewRemoteIsAdded_ShouldRet
 }
 
 func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRequiredFieldsAreEmpty_ShouldReturnError() {
-	suite.addRemote = NewAddRemote(nil, "", "", suite.validation)
+	suite.addRemote = NewAddRemote(nil, "", "")
 
 	err := suite.addRemote.NewRemote()
 
@@ -44,7 +42,7 @@ func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRequiredFieldsAreEmpty_Sho
 func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteCreationFails_ShouldReturnError() {
 	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
-	suite.addRemote = NewAddRemote(r, "new_origin", "https://github.com/neel1996/gitconvex-test.git", suite.validation)
+	suite.addRemote = NewAddRemote(r, "new_origin", "https://github.com/neel1996/gitconvex-test.git")
 
 	err := suite.addRemote.NewRemote()
 
diff --git a/git/remote/git_remote_delete.go b/git/remote/git_remote_delete.go
index d4e3b74..1821d8a 100644
--- a/git/remote/git_remote_delete.go
+++ b/git/remote/git_remote_delete.go
@@ -14,12 +14,11 @@ type Delete interface {
 type deleteRemote struct {
 	repo       *git2go.Repository
 	remoteName string
-	validate   Validation
 }
 
 // DeleteRemote deletes the remote based on the specified remoteName
 func (d deleteRemote) DeleteRemote() error {
-	if validationError := d.validateRemoteFields(); validationError != nil {
+	if validationError := NewRemoteValidation(d.repo).ValidateRemoteFields(); validationError != nil {
 		return validationError
 	}
 
@@ -54,10 +53,9 @@ func (d *deleteRemote) deleteSelectedRemote(remoteEntry string) error {
 	return nil
 }
 
-func NewDeleteRemote(repo *git2go.Repository, remoteName string, validate Validation) Delete {
+func NewDeleteRemote(repo *git2go.Repository, remoteName string) Delete {
 	return deleteRemote{
 		repo:       repo,
 		remoteName: remoteName,
-		validate:   validate,
 	}
 }
diff --git a/git/remote/git_remote_delete_test.go b/git/remote/git_remote_delete_test.go
index d2fa8f9..7a24790 100644
--- a/git/remote/git_remote_delete_test.go
+++ b/git/remote/git_remote_delete_test.go
@@ -11,7 +11,6 @@ import (
 type RemoteDeleteTestSuite struct {
 	suite.Suite
 	deleteRemote Delete
-	validation   Validation
 }
 
 func TestRemoteDeleteTestSuite(t *testing.T) {
@@ -23,8 +22,7 @@ func (suite *RemoteDeleteTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.validation = NewRemoteValidation()
-	suite.deleteRemote = NewDeleteRemote(r, "new_origin", suite.validation)
+	suite.deleteRemote = NewDeleteRemote(r, "new_origin")
 }
 
 func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenNewRemoteIsDeleted_ShouldReturnNoError() {
@@ -34,7 +32,7 @@ func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenNewRemoteIsDeleted_S
 }
 
 func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRequiredFieldsAreEmpty_ShouldReturnError() {
-	suite.deleteRemote = NewDeleteRemote(nil, "", suite.validation)
+	suite.deleteRemote = NewDeleteRemote(nil, "")
 
 	err := suite.deleteRemote.DeleteRemote()
 
@@ -44,7 +42,7 @@ func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRequiredFieldsAreEmp
 func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteDeletionFails_ShouldReturnError() {
 	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
-	suite.deleteRemote = NewDeleteRemote(r, "new_origin", suite.validation)
+	suite.deleteRemote = NewDeleteRemote(r, "new_origin")
 
 	err := suite.deleteRemote.DeleteRemote()
 
diff --git a/git/remote/git_remote_edit.go b/git/remote/git_remote_edit.go
index 4c7fda3..6439335 100644
--- a/git/remote/git_remote_edit.go
+++ b/git/remote/git_remote_edit.go
@@ -14,7 +14,6 @@ type editRemote struct {
 	repo       *git2go.Repository
 	remoteName string
 	remoteURL  string
-	validate   Validation
 }
 
 func (e editRemote) EditRemote() error {
@@ -45,7 +44,7 @@ func (e editRemote) EditRemote() error {
 }
 
 func (e editRemote) validateRemoteFields() error {
-	validationError := e.validate.ValidateRemoteFields(e.repo)
+	validationError := NewRemoteValidation(e.repo).ValidateRemoteFields()
 	if validationError != nil {
 		return validationError
 	}
@@ -56,11 +55,10 @@ func (e editRemote) validateRemoteFields() error {
 	return nil
 }
 
-func NewEditRemote(repo *git2go.Repository, remoteName string, remoteURL string, validation Validation) Edit {
+func NewEditRemote(repo *git2go.Repository, remoteName string, remoteURL string) Edit {
 	return editRemote{
 		repo:       repo,
 		remoteName: remoteName,
 		remoteURL:  remoteURL,
-		validate:   validation,
 	}
 }
diff --git a/git/remote/git_remote_edit_test.go b/git/remote/git_remote_edit_test.go
index ffec866..e656b24 100644
--- a/git/remote/git_remote_edit_test.go
+++ b/git/remote/git_remote_edit_test.go
@@ -25,8 +25,7 @@ func (suite *RemoteEditTestSuite) SetupTest() {
 		fmt.Println(err)
 	}
 	suite.repo = r
-	suite.validation = NewRemoteValidation()
-	suite.editRemote = NewEditRemote(r, "origin", "https://github.com/neel1996/gitconvex-test.git", suite.validation)
+	suite.editRemote = NewEditRemote(r, "origin", "https://github.com/neel1996/gitconvex-test.git")
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsEdited_ShouldReturnNil() {
@@ -36,7 +35,7 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsEdited_ShouldReturn
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoIsNil_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(nil, "origin", "https://github.com/neel1996/gitconvex-test.git", suite.validation)
+	suite.editRemote = NewEditRemote(nil, "origin", "https://github.com/neel1996/gitconvex-test.git")
 
 	wantErr := suite.editRemote.EditRemote()
 
@@ -46,7 +45,7 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoIsNil_ShouldReturnError
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteCollectionIsNil_ShouldReturnError() {
 	suite.editRemote = NewEditRemote(&git2go.Repository{
 		Remotes: git2go.RemoteCollection{},
-	}, "origin", "https://github.com/neel1996/gitconvex-test.git", suite.validation)
+	}, "origin", "https://github.com/neel1996/gitconvex-test.git")
 
 	wantErr := suite.editRemote.EditRemote()
 
@@ -54,7 +53,7 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteCollectionIsNil_Shoul
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteEditFieldsAreEmpty_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(suite.repo, "", "", suite.validation)
+	suite.editRemote = NewEditRemote(suite.repo, "", "")
 
 	wantErr := suite.editRemote.EditRemote()
 
diff --git a/git/remote/git_remote_list.go b/git/remote/git_remote_list.go
index 8892bf2..7e2d1e6 100644
--- a/git/remote/git_remote_list.go
+++ b/git/remote/git_remote_list.go
@@ -12,15 +12,14 @@ type List interface {
 }
 
 type listRemotes struct {
-	repo     *git2go.Repository
-	validate Validation
+	repo *git2go.Repository
 }
 
 func (l listRemotes) GetAllRemotes() []*model.RemoteDetails {
 	var remoteList []*model.RemoteDetails
 	repo := l.repo
 
-	if validationErr := l.validate.ValidateRemoteFields(repo); validationErr != nil {
+	if validationErr := NewRemoteValidation(repo).ValidateRemoteFields(); validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return nil
 	}
@@ -55,6 +54,6 @@ func (l listRemotes) GetAllRemotes() []*model.RemoteDetails {
 	return remoteList
 }
 
-func NewRemoteList(repo *git2go.Repository, validation Validation) List {
-	return listRemotes{repo: repo, validate: validation}
+func NewRemoteList(repo *git2go.Repository) List {
+	return listRemotes{repo: repo}
 }
diff --git a/git/remote/git_remote_list_test.go b/git/remote/git_remote_list_test.go
index 2045180..2ff1903 100644
--- a/git/remote/git_remote_list_test.go
+++ b/git/remote/git_remote_list_test.go
@@ -11,13 +11,11 @@ import (
 type ListRemoteTestSuite struct {
 	suite.Suite
 	listRemote List
-	validate   Validation
 }
 
 func (suite *ListRemoteTestSuite) SetupTest() {
 	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	suite.validate = NewRemoteValidation()
-	suite.listRemote = NewRemoteList(r, suite.validate)
+	suite.listRemote = NewRemoteList(r)
 }
 
 func TestListRemoteTestSuite(t *testing.T) {
@@ -38,7 +36,7 @@ func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsValid_ShouldReturn
 }
 
 func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsNil_ShouldReturnNil() {
-	suite.listRemote = NewRemoteList(nil, suite.validate)
+	suite.listRemote = NewRemoteList(nil)
 
 	remoteList := suite.listRemote.GetAllRemotes()
 
@@ -50,7 +48,7 @@ func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoHasNoRemotes_ShouldR
 		Remotes: git2go.RemoteCollection{},
 	}
 
-	suite.listRemote = NewRemoteList(r, suite.validate)
+	suite.listRemote = NewRemoteList(r)
 
 	remoteList := suite.listRemote.GetAllRemotes()
 
diff --git a/git/remote/git_remote_remote_name.go b/git/remote/git_remote_remote_name.go
index 36ef2b2..12908fd 100644
--- a/git/remote/git_remote_remote_name.go
+++ b/git/remote/git_remote_remote_name.go
@@ -13,13 +13,12 @@ type Name interface {
 type remoteName struct {
 	repo      *git2go.Repository
 	remoteUrl string
-	validate  Validation
 }
 
 func (r remoteName) GetRemoteNameWithUrl() string {
 	repo := r.repo
 
-	if validationErr := r.validate.ValidateRemoteFields(repo); validationErr != nil {
+	if validationErr := NewRemoteValidation(repo).ValidateRemoteFields(); validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return ""
 	}
@@ -55,10 +54,9 @@ func (r remoteName) isRemoteAvailable(remoteEntry *git2go.Remote, remote string)
 	return false
 }
 
-func NewGetRemoteName(repo *git2go.Repository, remoteUrl string, validate Validation) Name {
+func NewGetRemoteName(repo *git2go.Repository, remoteUrl string) Name {
 	return remoteName{
 		repo:      repo,
 		remoteUrl: remoteUrl,
-		validate:  validate,
 	}
 }
diff --git a/git/remote/git_remote_remote_name_test.go b/git/remote/git_remote_remote_name_test.go
index 1e423c1..b63ed0c 100644
--- a/git/remote/git_remote_remote_name_test.go
+++ b/git/remote/git_remote_remote_name_test.go
@@ -12,7 +12,6 @@ type GetRemoteNameTestSuite struct {
 	suite.Suite
 	getRemoteName Name
 	repo          *git2go.Repository
-	validation    Validation
 }
 
 func (suite *GetRemoteNameTestSuite) SetupTest() {
@@ -20,8 +19,7 @@ func (suite *GetRemoteNameTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.validation = NewRemoteValidation()
-	suite.getRemoteName = NewGetRemoteName(r, "https://github.com/neel1996/gitconvex-test.git", suite.validation)
+	suite.getRemoteName = NewGetRemoteName(r, "https://github.com/neel1996/gitconvex-test.git")
 }
 
 func TestGetRemoteNameTestSuite(t *testing.T) {
@@ -38,7 +36,7 @@ func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnRemoteName_Wh
 
 func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_WhenRepoIsNil() {
 	expectedRemote := ""
-	getRemoteName := NewGetRemoteName(nil, "https://github.com/neel1996/gitconvex-test.git", suite.validation)
+	getRemoteName := NewGetRemoteName(nil, "https://github.com/neel1996/gitconvex-test.git")
 
 	actualRemote := getRemoteName.GetRemoteNameWithUrl()
 
diff --git a/git/remote/git_remote_url_data.go b/git/remote/git_remote_url_data.go
index 4364631..1f83197 100644
--- a/git/remote/git_remote_url_data.go
+++ b/git/remote/git_remote_url_data.go
@@ -10,8 +10,7 @@ type ListRemoteUrl interface {
 }
 
 type listRemoteUrl struct {
-	repo       *git2go.Repository
-	validation Validation
+	repo *git2go.Repository
 }
 
 func (u listRemoteUrl) GetAllRemoteUrl() []*string {
@@ -19,7 +18,7 @@ func (u listRemoteUrl) GetAllRemoteUrl() []*string {
 
 	repo := u.repo
 
-	if validationErr := u.validation.ValidateRemoteFields(repo); validationErr != nil {
+	if validationErr := NewRemoteValidation(repo).ValidateRemoteFields(); validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return nil
 	}
@@ -46,6 +45,6 @@ func (u listRemoteUrl) GetAllRemoteUrl() []*string {
 	return remoteURL
 }
 
-func NewRemoteUrlData(repo *git2go.Repository, validation Validation) ListRemoteUrl {
-	return listRemoteUrl{repo: repo, validation: validation}
+func NewRemoteUrlData(repo *git2go.Repository) ListRemoteUrl {
+	return listRemoteUrl{repo: repo}
 }
diff --git a/git/remote/git_remote_url_data_test.go b/git/remote/git_remote_url_data_test.go
index d38b1e9..507d039 100644
--- a/git/remote/git_remote_url_data_test.go
+++ b/git/remote/git_remote_url_data_test.go
@@ -10,7 +10,6 @@ import (
 type RemoteUrlDataTestSuite struct {
 	suite.Suite
 	listRemoteUrl ListRemoteUrl
-	validation    Validation
 }
 
 func TestRemoteUrlDataTestSuite(t *testing.T) {
@@ -19,8 +18,7 @@ func TestRemoteUrlDataTestSuite(t *testing.T) {
 
 func (suite *RemoteUrlDataTestSuite) SetupTest() {
 	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	suite.validation = NewRemoteValidation()
-	suite.listRemoteUrl = NewRemoteUrlData(r, suite.validation)
+	suite.listRemoteUrl = NewRemoteUrlData(r)
 }
 
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesArePresent_ShouldReturnRemoteUrlList() {
@@ -31,7 +29,7 @@ func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesArePresent_S
 }
 
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoIsNil_ShouldReturnNil() {
-	suite.listRemoteUrl = NewRemoteUrlData(nil, suite.validation)
+	suite.listRemoteUrl = NewRemoteUrlData(nil)
 
 	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
 
@@ -39,12 +37,9 @@ func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoIsNil_ShouldRet
 }
 
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesAreNil_ShouldReturnNil() {
-	suite.listRemoteUrl = NewRemoteUrlData(
-		&git2go.Repository{
-			Remotes: git2go.RemoteCollection{},
-		},
-		suite.validation,
-	)
+	suite.listRemoteUrl = NewRemoteUrlData(&git2go.Repository{
+		Remotes: git2go.RemoteCollection{},
+	})
 
 	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
 
diff --git a/git/remote/remote_validation.go b/git/remote/remote_validation.go
index 23d4c15..09253f4 100644
--- a/git/remote/remote_validation.go
+++ b/git/remote/remote_validation.go
@@ -6,16 +6,14 @@ import (
 )
 
 type Validation interface {
-	ValidateRemoteFields(*git2go.Repository) error
+	ValidateRemoteFields() error
 }
 
 type validation struct {
 	repo *git2go.Repository
 }
 
-func (v validation) ValidateRemoteFields(repository *git2go.Repository) error {
-	v.repo = repository
-
+func (v validation) ValidateRemoteFields() error {
 	validateRepoErr := v.validateRepo()
 	if validateRepoErr != nil {
 		return validateRepoErr
@@ -45,6 +43,8 @@ func (v validation) validateRemoteCollection() error {
 	return nil
 }
 
-func NewRemoteValidation() Validation {
-	return validation{}
+func NewRemoteValidation(repo *git2go.Repository) Validation {
+	return validation{
+		repo: repo,
+	}
 }
diff --git a/git/remote/remote_validation_test.go b/git/remote/remote_validation_test.go
index 4456392..358daf9 100644
--- a/git/remote/remote_validation_test.go
+++ b/git/remote/remote_validation_test.go
@@ -24,11 +24,11 @@ func (suite *RemoteValidationTestSuite) SetupTest() {
 		fmt.Println(err)
 	}
 	suite.repo = r
-	suite.validateRemoteFields = NewRemoteValidation()
+	suite.validateRemoteFields = NewRemoteValidation(suite.repo)
 }
 
 func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenAllFieldsAreValid_ShouldReturnNil() {
-	wantErr := suite.validateRemoteFields.ValidateRemoteFields(suite.repo)
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields()
 
 	fmt.Println(wantErr)
 
@@ -36,7 +36,8 @@ func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenAllFieldsAr
 }
 
 func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRepoIsNil_ShouldReturnError() {
-	wantErr := suite.validateRemoteFields.ValidateRemoteFields(nil)
+	suite.validateRemoteFields = NewRemoteValidation(nil)
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields()
 	wantErrorText := "repo is nil"
 
 	suite.NotNil(wantErr)
@@ -44,9 +45,10 @@ func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRepoIsNil_S
 }
 
 func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRemoteCollectionIsNil_ShouldReturnError() {
-	wantErr := suite.validateRemoteFields.ValidateRemoteFields(&git2go.Repository{
+	suite.validateRemoteFields = NewRemoteValidation(&git2go.Repository{
 		Remotes: git2go.RemoteCollection{},
 	})
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields()
 	wantErrorText := "remote collection is nil"
 
 	suite.NotNil(wantErr)
diff --git a/init/init_remote.go b/init/init_remote.go
index 1f6ce0b..0842ecb 100644
--- a/init/init_remote.go
+++ b/init/init_remote.go
@@ -26,14 +26,12 @@ func RemoteObjects(ctx context.Context) Remote {
 	remoteName := ctx.Value(RemoteName).(string)
 	remoteUrl := ctx.Value(RemoteUrl).(string)
 
-	remoteValidation := remote.NewRemoteValidation()
-
-	addRemote := remote.NewAddRemote(repo, remoteName, remoteUrl, remoteValidation)
-	deleteRemote := remote.NewDeleteRemote(repo, remoteName, remoteValidation)
-	editRemote := remote.NewEditRemote(repo, remoteName, remoteUrl, remoteValidation)
-	listRemote := remote.NewRemoteList(repo, remoteValidation)
-	name := remote.NewGetRemoteName(repo, remoteUrl, remoteValidation)
-	listRemoteURL := remote.NewRemoteUrlData(repo, remoteValidation)
+	addRemote := remote.NewAddRemote(repo, remoteName, remoteUrl)
+	deleteRemote := remote.NewDeleteRemote(repo, remoteName)
+	editRemote := remote.NewEditRemote(repo, remoteName, remoteUrl)
+	listRemote := remote.NewRemoteList(repo)
+	name := remote.NewGetRemoteName(repo, remoteUrl)
+	listRemoteURL := remote.NewRemoteUrlData(repo)
 
 	return Remote{
 		AddRemote:     addRemote,

From 009bf0307ec7fc570b5ff63443ef203f732081da Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 1 Jul 2021 23:56:05 +0530
Subject: [PATCH 030/148] add new test suites for the branch apis

---
 git/branch/branch_validation.go        |  12 ++-
 git/branch/git_branch_add.go           |  10 +-
 git/branch/git_branch_checkout.go      |   4 +-
 git/branch/git_branch_checkout_test.go |   5 +-
 git/branch/git_branch_compare.go       |   7 +-
 git/branch/git_branch_compare_test.go  | 141 +++++++++++++++++++++++++
 git/branch/git_branch_delete.go        |  25 +++--
 git/branch/git_branch_delete_test.go   |  88 +++++++++++++++
 graph/model/aux_models.go              |   6 ++
 tests/git_branch_compare_test.go       |  65 ------------
 tests/git_branch_delete_test.go        |  45 --------
 11 files changed, 268 insertions(+), 140 deletions(-)
 create mode 100644 git/branch/git_branch_compare_test.go
 create mode 100644 git/branch/git_branch_delete_test.go
 delete mode 100644 tests/git_branch_compare_test.go
 delete mode 100644 tests/git_branch_delete_test.go

diff --git a/git/branch/branch_validation.go b/git/branch/branch_validation.go
index 2e0f663..5bc9c00 100644
--- a/git/branch/branch_validation.go
+++ b/git/branch/branch_validation.go
@@ -11,7 +11,7 @@ type Validation interface {
 
 type validateBranch struct {
 	repo       *git2go.Repository
-	branchName string
+	branchName []string
 }
 
 func (v validateBranch) ValidateBranchFields() error {
@@ -20,15 +20,17 @@ func (v validateBranch) ValidateBranchFields() error {
 		return errors.New(err)
 	}
 
-	if v.branchName == "" {
-		err := "branch name is empty"
-		return errors.New(err)
+	for _, branchName := range v.branchName {
+		if branchName == "" {
+			err := "branch name is empty"
+			return errors.New(err)
+		}
 	}
 
 	return nil
 }
 
-func NewBranchFieldsValidation(repo *git2go.Repository, branchName string) Validation {
+func NewBranchFieldsValidation(repo *git2go.Repository, branchName ...string) Validation {
 	return validateBranch{
 		repo:       repo,
 		branchName: branchName,
diff --git a/git/branch/git_branch_add.go b/git/branch/git_branch_add.go
index ec39791..7e8c6bd 100644
--- a/git/branch/git_branch_add.go
+++ b/git/branch/git_branch_add.go
@@ -1,7 +1,6 @@
 package branch
 
 import (
-	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
@@ -54,12 +53,9 @@ func (a addBranch) AddBranch() error {
 }
 
 func (a addBranch) validateAddBranchFields() error {
-	if a.repo == nil {
-		return errors.New("repo is nil")
-	}
-
-	if a.branchName == "" {
-		return errors.New("branch name is empty")
+	err := NewBranchFieldsValidation(a.repo, a.branchName).ValidateBranchFields()
+	if err != nil {
+		return err
 	}
 	return nil
 }
diff --git a/git/branch/git_branch_checkout.go b/git/branch/git_branch_checkout.go
index 6a42237..b024594 100644
--- a/git/branch/git_branch_checkout.go
+++ b/git/branch/git_branch_checkout.go
@@ -45,9 +45,7 @@ func (b branchCheckout) CheckoutBranch() error {
 }
 
 func (b branchCheckout) validateBranchFields() error {
-	validation := NewBranchFieldsValidation(b.repo, b.branchName)
-	err := validation.ValidateBranchFields()
-	if err != nil {
+	if err := NewBranchFieldsValidation(b.repo, b.branchName).ValidateBranchFields(); err != nil {
 		logger.Log(err.Error(), global.StatusError)
 		return err
 	}
diff --git a/git/branch/git_branch_checkout_test.go b/git/branch/git_branch_checkout_test.go
index bc95b0e..6f6dae0 100644
--- a/git/branch/git_branch_checkout_test.go
+++ b/git/branch/git_branch_checkout_test.go
@@ -24,13 +24,12 @@ func (suite *BranchCheckoutTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-
+	suite.repo = r
 	suite.branchName = "test_checkout"
-	addErr := NewAddBranch(r, suite.branchName, false, nil).AddBranch()
+	addErr := NewAddBranch(suite.repo, suite.branchName, false, nil).AddBranch()
 	if addErr != nil {
 		fmt.Println(addErr)
 	}
-	suite.repo = r
 	suite.checkoutBranch = NewBranchCheckout(suite.repo, suite.branchName)
 }
 
diff --git a/git/branch/git_branch_compare.go b/git/branch/git_branch_compare.go
index bea693e..c55e348 100644
--- a/git/branch/git_branch_compare.go
+++ b/git/branch/git_branch_compare.go
@@ -1,6 +1,7 @@
 package branch
 
 import (
+	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
@@ -33,11 +34,15 @@ func (b branchCompare) CompareBranch() []*model.BranchCompareResults {
 	var filteredCommits []model.GitCommits
 	repo := b.repo
 
+	if err := NewBranchFieldsValidation(repo, b.baseBranch, b.diffBranch).ValidateBranchFields(); err != nil {
+		return returnBranchCompareError(err.Error())
+	}
+
 	baseBranch, baseBranchErr := repo.LookupBranch(b.baseBranch, git2go.BranchLocal)
 	compareBranch, compareBranchErr := repo.LookupBranch(b.diffBranch, git2go.BranchLocal)
 
 	if baseBranchErr != nil || compareBranchErr != nil {
-		return returnBranchCompareError("Unable to lookup target branches from the repo")
+		return returnBranchCompareError(fmt.Sprintf("Unable to lookup target branches from the repo : %v %v", baseBranchErr, compareBranchErr))
 	}
 
 	compareResult := baseBranch.Cmp(compareBranch.Reference)
diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
new file mode 100644
index 0000000..005660e
--- /dev/null
+++ b/git/branch/git_branch_compare_test.go
@@ -0,0 +1,141 @@
+package branch
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/stretchr/testify/suite"
+	"io/ioutil"
+	"os"
+	"testing"
+	"time"
+)
+
+type BranchCompareTestSuite struct {
+	suite.Suite
+	branchCompare Compare
+	repo          *git2go.Repository
+	baseBranch    string
+	compareBranch string
+	testFile      string
+}
+
+func TestBranchCompareTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchCompareTestSuite))
+}
+
+func (suite *BranchCompareTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = r
+	suite.baseBranch = "master"
+	suite.compareBranch = "new_compare"
+	suite.branchCompare = NewBranchCompare(suite.repo, suite.baseBranch, suite.compareBranch)
+}
+
+func (suite *BranchCompareTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = r
+	suite.testFile = os.Getenv("GITCONVEX_TEST_REPO") + "/" + "compare_test.txt"
+	suite.baseBranch = "master"
+	suite.compareBranch = "new_compare"
+	addErr := NewAddBranch(r, suite.compareBranch, false, nil).AddBranch()
+	if addErr != nil {
+		fmt.Println(addErr)
+	}
+	suite.stageAndCommitTestFile()
+}
+
+func (suite *BranchCompareTestSuite) TearDownSuite() {
+	checkoutErr := NewBranchCheckout(suite.repo, suite.baseBranch).CheckoutBranch()
+	if checkoutErr != nil {
+		logger.Log(checkoutErr.Error(), global.StatusError)
+		return
+	}
+
+	err := os.Remove(suite.testFile)
+	if err != nil {
+		return
+	}
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchesHaveDifferentCommits_ShouldReturnDifference() {
+	compareResults := suite.branchCompare.CompareBranch()
+
+	currentTime := time.Now()
+	timeString := time.Date(
+		currentTime.Year(),
+		currentTime.Month(),
+		currentTime.Day(),
+		0,
+		0,
+		0,
+		0,
+		time.UTC,
+	).String()
+
+	suite.Len(compareResults, 1)
+
+	suite.Len(compareResults[0].Commits, 1)
+	suite.NotNil(*compareResults[0].Commits[0])
+	suite.NotEmpty(*compareResults[0].Commits[0].CommitMessage)
+	suite.Contains(timeString, compareResults[0].Date)
+	suite.Equal(1, len(compareResults[0].Commits))
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenRepoIsNil_ShouldReturnEmptyDifference() {
+	suite.branchCompare = NewBranchCompare(nil, suite.baseBranch, suite.compareBranch)
+	compareResults := suite.branchCompare.CompareBranch()
+
+	suite.Len(compareResults, 0)
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenEitherOfBranchInputIsEmpty_ShouldReturnEmptyDifference() {
+	suite.branchCompare = NewBranchCompare(suite.repo, "", suite.compareBranch)
+	compareResults := suite.branchCompare.CompareBranch()
+
+	suite.Len(compareResults, 0)
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchDoesNotExist_ShouldReturnEmptyDifference() {
+	suite.branchCompare = NewBranchCompare(suite.repo, suite.baseBranch, "no_exists")
+	compareResults := suite.branchCompare.CompareBranch()
+
+	suite.Len(compareResults, 0)
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchDoesNotDiffer_ShouldReturnEmptyDifference() {
+	suite.branchCompare = NewBranchCompare(suite.repo, suite.baseBranch, suite.baseBranch)
+	compareResults := suite.branchCompare.CompareBranch()
+
+	suite.Len(compareResults, 0)
+}
+
+func (suite *BranchCompareTestSuite) stageAndCommitTestFile() {
+	err := ioutil.WriteFile(suite.testFile, []byte{0}, 0644)
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return
+	}
+	checkoutErr := NewBranchCheckout(suite.repo, suite.compareBranch).CheckoutBranch()
+	if checkoutErr != nil {
+		logger.Log(checkoutErr.Error(), global.StatusError)
+		return
+	}
+	git.StageItemStruct{
+		Repo:     suite.repo,
+		FileItem: suite.testFile,
+	}.StageItem()
+
+	git.CommitStruct{
+		Repo:          suite.repo,
+		CommitMessage: "Branch compare test commit",
+		RepoPath:      suite.repo.Workdir(),
+	}.CommitChanges()
+}
diff --git a/git/branch/git_branch_delete.go b/git/branch/git_branch_delete.go
index 59c977a..80c4d1e 100644
--- a/git/branch/git_branch_delete.go
+++ b/git/branch/git_branch_delete.go
@@ -4,11 +4,10 @@ import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
 )
 
 type Delete interface {
-	DeleteBranch() *model.BranchDeleteStatus
+	DeleteBranch() error
 }
 
 type deleteBranch struct {
@@ -17,26 +16,30 @@ type deleteBranch struct {
 }
 
 // DeleteBranch deletes a branch from the repo
-func (inputs deleteBranch) DeleteBranch() *model.BranchDeleteStatus {
-	repo := inputs.repo
-	branchName := inputs.branchName
-	branch, deleteBranchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
+func (d deleteBranch) DeleteBranch() error {
+	repo := d.repo
+	branchName := d.branchName
+
+	validationErr := NewBranchFieldsValidation(repo, branchName).ValidateBranchFields()
+	if validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return validationErr
+	}
 
+	branch, deleteBranchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
 	if deleteBranchErr != nil {
 		logger.Log(fmt.Sprintf("Failed to delete branch %s -> %v", branchName, deleteBranchErr.Error()), global.StatusError)
-		return &model.BranchDeleteStatus{Status: global.BranchDeleteError}
+		return deleteBranchErr
 	}
 
 	deleteErr := branch.Delete()
 	if deleteErr != nil {
 		logger.Log(fmt.Sprintf("Failed to delete branch %s -> %v", branchName, deleteErr.Error()), global.StatusError)
-		return &model.BranchDeleteStatus{Status: global.BranchDeleteError}
+		return deleteErr
 	}
 
 	logger.Log(fmt.Sprintf("Branch - %s has been removed from the repo", branchName), global.StatusInfo)
-	return &model.BranchDeleteStatus{
-		Status: global.BranchDeleteSuccess,
-	}
+	return nil
 }
 
 func NewDeleteBranch(repo *git2go.Repository, branchName string) Delete {
diff --git a/git/branch/git_branch_delete_test.go b/git/branch/git_branch_delete_test.go
new file mode 100644
index 0000000..eab2459
--- /dev/null
+++ b/git/branch/git_branch_delete_test.go
@@ -0,0 +1,88 @@
+package branch
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type BranchDeleteTestSuite struct {
+	suite.Suite
+	branchDelete Delete
+	branchName   string
+	repo         *git2go.Repository
+}
+
+func TestBranchDeleteTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchDeleteTestSuite))
+}
+
+func (suite *BranchDeleteTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = r
+	suite.branchName = "delete_branch"
+	suite.branchDelete = NewDeleteBranch(suite.repo, suite.branchName)
+}
+
+func (suite *BranchDeleteTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = r
+	suite.branchName = "delete_branch"
+	addErr := NewAddBranch(suite.repo, suite.branchName, false, nil).AddBranch()
+	if addErr != nil {
+		fmt.Println(addErr)
+	}
+}
+
+func (suite *BranchDeleteTestSuite) TearDownSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	_ = NewBranchCheckout(r, "master").CheckoutBranch()
+}
+
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchIsDeleted_ShouldReturnNil() {
+	err := suite.branchDelete.DeleteBranch()
+
+	suite.Nil(err)
+}
+
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenRepoIsNil_ShouldReturnError() {
+	suite.branchDelete = NewDeleteBranch(nil, suite.branchName)
+	err := suite.branchDelete.DeleteBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchNameIsEmpty_ShouldReturnError() {
+	suite.branchDelete = NewDeleteBranch(suite.repo, "")
+	err := suite.branchDelete.DeleteBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchDoesNotExists_ShouldReturnError() {
+	suite.branchDelete = NewDeleteBranch(suite.repo, "no_exists")
+	err := suite.branchDelete.DeleteBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchIsCurrentBranch_ShouldReturnError() {
+	head, _ := suite.repo.Head()
+	name, _ := head.Branch().Name()
+
+	suite.branchDelete = NewDeleteBranch(suite.repo, name)
+	err := suite.branchDelete.DeleteBranch()
+
+	suite.NotNil(err)
+}
diff --git a/graph/model/aux_models.go b/graph/model/aux_models.go
index 43b11b9..53887b7 100644
--- a/graph/model/aux_models.go
+++ b/graph/model/aux_models.go
@@ -18,3 +18,9 @@ type NewRepoInputs struct {
 	UserName    *string
 	Password    *string
 }
+
+type ListOfBranches struct {
+	CurrentBranch string
+	BranchList    []string
+	AllBranchList []string
+}
diff --git a/tests/git_branch_compare_test.go b/tests/git_branch_compare_test.go
deleted file mode 100644
index b165cf4..0000000
--- a/tests/git_branch_compare_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package tests
-
-import (
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/git"
-	"github.com/neel1996/gitconvex/git/branch"
-	"github.com/stretchr/testify/assert"
-	"io/ioutil"
-	"os"
-	"testing"
-)
-
-func Test_branchCompare_CompareBranch(t *testing.T) {
-	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-
-	type fields struct {
-		repo       *git2go.Repository
-		baseBranch string
-		diffBranch string
-	}
-	tests := []struct {
-		name   string
-		fields fields
-	}{
-		{name: "Branch compare test", fields: struct {
-			repo       *git2go.Repository
-			baseBranch string
-			diffBranch string
-		}{repo: r, baseBranch: "master", diffBranch: "test_compare"}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			branch.NewAddBranch(r, tt.fields.diffBranch, false, nil).AddBranch()
-			branch.NewBranchCheckout(r, tt.fields.diffBranch).CheckoutBranch()
-			setupTestRepoStageAndCommit("Comparison commit for branch compare")
-
-			branch.NewBranchCheckout(r, tt.fields.baseBranch).CheckoutBranch()
-
-			b := branch.NewBranchCompare(r, tt.fields.baseBranch, tt.fields.diffBranch)
-			got := b.CompareBranch()
-
-			assert.NotEmpty(t, got)
-		})
-	}
-}
-
-func setupTestRepoStageAndCommit(msg string) bool {
-	testRepo := os.Getenv("GITCONVEX_TEST_REPO")
-	repository, repoErr := git2go.OpenRepository(testRepo)
-	if repoErr != nil {
-		return true
-	}
-
-	initFile := "init_file.txt"
-	_ = ioutil.WriteFile(testRepo+"/"+initFile, []byte{byte(63)}, 0755)
-
-	git.StageAllStruct{Repo: repository}.StageAllItems()
-	git.CommitStruct{
-		Repo:          repository,
-		CommitMessage: msg,
-		RepoPath:      testRepo,
-	}.CommitChanges()
-
-	return false
-}
diff --git a/tests/git_branch_delete_test.go b/tests/git_branch_delete_test.go
deleted file mode 100644
index ceefde5..0000000
--- a/tests/git_branch_delete_test.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/git/branch"
-	"github.com/neel1996/gitconvex/graph/model"
-	"github.com/stretchr/testify/assert"
-	"os"
-	"testing"
-)
-
-func TestDeleteBranch(t *testing.T) {
-	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-
-	type args struct {
-		repo       *git.Repository
-		branchName string
-	}
-	tests := []struct {
-		name string
-		args args
-		want *model.BranchDeleteStatus
-	}{
-		{name: "Git branch deletion test case", args: struct {
-			repo       *git.Repository
-			branchName string
-		}{repo: r, branchName: "test"}, want: &model.BranchDeleteStatus{Status: "BRANCH_DELETE_SUCCESS"}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			b := branch.Operation{
-				Delete: branch.NewDeleteBranch(r, "test"),
-				Add:    branch.NewAddBranch(r, "test", false, nil),
-			}
-
-			_, err := b.GitAddBranch()
-			assert.Nil(t, err)
-
-			got, err := b.GitDeleteBranch()
-
-			assert.Nil(t, err)
-			assert.Equal(t, tt.want, got)
-		})
-	}
-}

From a9a5340616c341e4955f8c4cbd5ee50433a64016 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 2 Jul 2021 23:59:59 +0530
Subject: [PATCH 031/148] update branch list api

---
 git/branch/branch.go               | 20 +++++----
 git/branch/git_branch_list.go      | 66 +++++++++++++++---------------
 git/branch/git_branch_list_test.go | 30 ++++++++++++++
 3 files changed, 75 insertions(+), 41 deletions(-)
 create mode 100644 git/branch/git_branch_list_test.go

diff --git a/git/branch/branch.go b/git/branch/branch.go
index d3c845d..15fd00e 100644
--- a/git/branch/branch.go
+++ b/git/branch/branch.go
@@ -12,7 +12,7 @@ type Branch interface {
 	GitAddBranch() (string, error)
 	GitCheckoutBranch() (string, error)
 	GitCompareBranches() ([]*model.BranchCompareResults, error)
-	GitListBranches(chan ListOfBranches)
+	GitListBranches() (model.ListOfBranches, error)
 }
 
 type Operation struct {
@@ -54,16 +54,20 @@ func (b Operation) GitCompareBranches() ([]*model.BranchCompareResults, error) {
 }
 
 func (b Operation) GitDeleteBranch() (*model.BranchDeleteStatus, error) {
-	deleteStatus := b.Delete.DeleteBranch()
+	err := b.Delete.DeleteBranch()
 
-	if deleteStatus.Status == global.BranchDeleteError {
-		return nil, errors.New("branch deletion failed")
+	if err != nil {
+		return &model.BranchDeleteStatus{Status: global.BranchDeleteError}, err
 	}
 
-	return deleteStatus, nil
+	return &model.BranchDeleteStatus{Status: global.BranchDeleteSuccess}, nil
 }
 
-func (b Operation) GitListBranches(branchChannel chan ListOfBranches) {
-	b.List.ListBranches(branchChannel)
-}
+func (b Operation) GitListBranches() (model.ListOfBranches, error) {
+	listOfBranches, err := b.List.ListBranches()
+	if err != nil {
+		return model.ListOfBranches{}, err
+	}
 
+	return listOfBranches, nil
+}
diff --git a/git/branch/git_branch_list.go b/git/branch/git_branch_list.go
index df3bdcf..299c48e 100644
--- a/git/branch/git_branch_list.go
+++ b/git/branch/git_branch_list.go
@@ -4,70 +4,68 @@ import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
 	"go/types"
 	"strings"
 )
 
 type List interface {
-	ListBranches(branchChan chan ListOfBranches)
+	ListBranches() (model.ListOfBranches, error)
 }
 
 type listBranch struct {
 	repo            *git2go.Repository
-	localBranchList []*string
-	allBranchList   []*string
-}
-
-type ListOfBranches struct {
-	CurrentBranch string
-	BranchList    []*string
-	AllBranchList []*string
+	localBranchList []string
+	allBranchList   []string
 }
 
 // ListBranches fetches all the branches from the target repository
 // The result will be returned as a struct with the current branch and all the available branches
-func (l listBranch) ListBranches(branchChan chan ListOfBranches) {
+func (l listBranch) ListBranches() (model.ListOfBranches, error) {
 	var currentBranch string
 	repo := l.repo
 
-	defer close(branchChan)
+	validationErr := NewBranchFieldsValidation(repo).ValidateBranchFields()
+	if validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return model.ListOfBranches{}, validationErr
+	}
 
 	head, headErr := repo.Head()
-
 	if headErr != nil {
 		logger.Log(fmt.Sprintf("Repo head is invalid -> %s", headErr.Error()), global.StatusError)
-		nilMsg := []string{"No Branches available", "Repo HEAD is nil"}
-		branchChan <- ListOfBranches{
-			BranchList:    []*string{&nilMsg[0]},
-			CurrentBranch: nilMsg[1],
-			AllBranchList: []*string{&nilMsg[0]},
-		}
-		return
+		return model.ListOfBranches{}, headErr
 	}
 
 	currentBranch = getCurrentBranchName(head)
 
-	l.allBranchList = append(l.allBranchList, &currentBranch)
-	l.localBranchList = append(l.localBranchList, &currentBranch)
+	l.allBranchList = append(l.allBranchList, currentBranch)
+	l.localBranchList = append(l.localBranchList, currentBranch)
 
 	localBranchIterator, itrErr := repo.NewBranchIterator(git2go.BranchAll)
+	if itrErr != nil {
+		logger.Log(itrErr.Error(), global.StatusError)
+		return model.ListOfBranches{}, itrErr
+	}
 
-	if itrErr == nil {
-		l.runBranchIterator(localBranchIterator, currentBranch)
+	err := l.runBranchIterator(localBranchIterator, currentBranch)
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return model.ListOfBranches{}, err
 	}
 
-	branchChan <- ListOfBranches{
-		BranchList:    l.localBranchList,
+	return model.ListOfBranches{
 		CurrentBranch: currentBranch,
+		BranchList:    l.localBranchList,
 		AllBranchList: l.allBranchList,
-	}
+	}, nil
 }
 
-func (l listBranch) runBranchIterator(localBranchIterator *git2go.BranchIterator, currentBranch string) {
-	_ = localBranchIterator.ForEach(func(branch *git2go.Branch, branchType git2go.BranchType) error {
+func (l listBranch) runBranchIterator(localBranchIterator *git2go.BranchIterator, currentBranch string) error {
+	err := localBranchIterator.ForEach(func(branch *git2go.Branch, branchType git2go.BranchType) error {
 		branchName, nameErr := branch.Name()
 		if nameErr != nil {
-			return types.Error{Msg: "branch iterator end"}
+			return types.Error{Msg: "Unable to fetch branch name"}
 		}
 
 		if !branch.IsTag() && !branch.IsNote() && branchName != currentBranch {
@@ -75,14 +73,16 @@ func (l listBranch) runBranchIterator(localBranchIterator *git2go.BranchIterator
 		}
 		return nil
 	})
+
+	return err
 }
 
 func (l listBranch) classifyRemoteAndLocalBranches(branch *git2go.Branch, branchName string, currentBranch string) {
 	if branch.IsRemote() && strings.Contains(branchName, "/") {
 		l.getRemoteBranchName(branchName, currentBranch)
 	} else {
-		l.allBranchList = append(l.allBranchList, &branchName)
-		l.localBranchList = append(l.localBranchList, &branchName)
+		l.allBranchList = append(l.allBranchList, branchName)
+		l.localBranchList = append(l.localBranchList, branchName)
 	}
 }
 
@@ -92,7 +92,7 @@ func (l listBranch) getRemoteBranchName(branchName string, currentBranch string)
 
 	if splitBranch != "HEAD" && splitBranch != currentBranch {
 		concatRemote := "remotes/" + strings.Join(splitString, "/")
-		l.allBranchList = append(l.allBranchList, &concatRemote)
+		l.allBranchList = append(l.allBranchList, concatRemote)
 	}
 }
 
@@ -103,7 +103,7 @@ func getCurrentBranchName(head *git2go.Reference) string {
 	return branch
 }
 
-func NewBranchListInterface(repo *git2go.Repository) List {
+func NewBranchList(repo *git2go.Repository) List {
 	return listBranch{
 		repo: repo,
 	}
diff --git a/git/branch/git_branch_list_test.go b/git/branch/git_branch_list_test.go
new file mode 100644
index 0000000..c61207b
--- /dev/null
+++ b/git/branch/git_branch_list_test.go
@@ -0,0 +1,30 @@
+package branch
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type BranchListTestSuite struct {
+	suite.Suite
+	repo       *git2go.Repository
+	branchList List
+}
+
+func TestBranchListTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchListTestSuite))
+}
+
+func (suite *BranchListTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = r
+	suite.branchList = NewBranchList(suite.repo)
+}
+
+func  (suite *BranchListTestSuite)
\ No newline at end of file

From 6701f3982c7cfcfc4a93255340b2fbba0c5b8cff Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 3 Jul 2021 20:25:11 +0530
Subject: [PATCH 032/148] update branch list api with new test suite

---
 api/repo_status.go                    | 14 ++++-----
 git/branch/git_branch_compare_test.go | 28 ++++++++---------
 git/branch/git_branch_list.go         | 21 +++++++------
 git/branch/git_branch_list_test.go    | 31 ++++++++++++++++++-
 tests/git_branch_list_test.go         | 44 ---------------------------
 utils/array_generator.go.go           | 11 +++++++
 6 files changed, 73 insertions(+), 76 deletions(-)
 delete mode 100644 tests/git_branch_list_test.go
 create mode 100644 utils/array_generator.go.go

diff --git a/api/repo_status.go b/api/repo_status.go
index 0149410..8632e1b 100644
--- a/api/repo_status.go
+++ b/api/repo_status.go
@@ -15,7 +15,6 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	logger.Log("Collecting repo status information", global.StatusInfo)
 
 	repoChan := make(chan git.RepoDetails)
-	branchChan := make(chan branch.ListOfBranches)
 	commitChan := make(chan git.AllCommitData)
 	trackedFileCountChan := make(chan int)
 
@@ -84,12 +83,11 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 		*remoteURL = *remotes[0]
 	}
 
-	branchListObj := branch.NewBranchListInterface(repo)
+	branchListObj := branch.NewBranchList(repo)
 	b := branch.Operation{List: branchListObj}
-	go b.GitListBranches(branchChan)
+	branchList, _ := b.GitListBranches()
 
-	branchList := <-branchChan
-	currentBranch := &branchList.CurrentBranch
+	currentBranch := branchList.CurrentBranch
 	branches := branchList.BranchList
 	allBranches := branchList.AllBranchList
 
@@ -116,9 +114,9 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	return &model.GitRepoStatusResults{
 		GitRemoteData:        remoteURL,
 		GitRepoName:          repoName,
-		GitBranchList:        branches,
-		GitAllBranchList:     allBranches,
-		GitCurrentBranch:     currentBranch,
+		GitBranchList:        utils.GeneratePointerArrayFrom(branches),
+		GitAllBranchList:     utils.GeneratePointerArrayFrom(allBranches),
+		GitCurrentBranch:     &currentBranch,
 		GitRemoteHost:        &remoteName,
 		GitTotalCommits:      totalCommitsPtr,
 		GitLatestCommit:      latestCommit,
diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
index 005660e..b346311 100644
--- a/git/branch/git_branch_compare_test.go
+++ b/git/branch/git_branch_compare_test.go
@@ -25,31 +25,31 @@ func TestBranchCompareTestSuite(t *testing.T) {
 	suite.Run(t, new(BranchCompareTestSuite))
 }
 
-func (suite *BranchCompareTestSuite) SetupTest() {
+func (suite *BranchCompareTestSuite) SetupSuite() {
 	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	if err != nil {
 		fmt.Println(err)
 	}
 	suite.repo = r
+	suite.testFile = os.Getenv("GITCONVEX_TEST_REPO") + "/" + "compare_test.txt"
 	suite.baseBranch = "master"
 	suite.compareBranch = "new_compare"
-	suite.branchCompare = NewBranchCompare(suite.repo, suite.baseBranch, suite.compareBranch)
+	addErr := NewAddBranch(r, suite.compareBranch, false, nil).AddBranch()
+	if addErr != nil {
+		fmt.Println(addErr)
+	}
+	suite.stageAndCommitTestFile()
 }
 
-func (suite *BranchCompareTestSuite) SetupSuite() {
+func (suite *BranchCompareTestSuite) SetupTest() {
 	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	if err != nil {
 		fmt.Println(err)
 	}
 	suite.repo = r
-	suite.testFile = os.Getenv("GITCONVEX_TEST_REPO") + "/" + "compare_test.txt"
 	suite.baseBranch = "master"
 	suite.compareBranch = "new_compare"
-	addErr := NewAddBranch(r, suite.compareBranch, false, nil).AddBranch()
-	if addErr != nil {
-		fmt.Println(addErr)
-	}
-	suite.stageAndCommitTestFile()
+	suite.branchCompare = NewBranchCompare(suite.repo, suite.baseBranch, suite.compareBranch)
 }
 
 func (suite *BranchCompareTestSuite) TearDownSuite() {
@@ -118,16 +118,16 @@ func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchDoesNotDiffer_S
 }
 
 func (suite *BranchCompareTestSuite) stageAndCommitTestFile() {
-	err := ioutil.WriteFile(suite.testFile, []byte{0}, 0644)
-	if err != nil {
-		logger.Log(err.Error(), global.StatusError)
-		return
-	}
 	checkoutErr := NewBranchCheckout(suite.repo, suite.compareBranch).CheckoutBranch()
 	if checkoutErr != nil {
 		logger.Log(checkoutErr.Error(), global.StatusError)
 		return
 	}
+	err := ioutil.WriteFile(suite.testFile, []byte{0}, 0644)
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return
+	}
 	git.StageItemStruct{
 		Repo:     suite.repo,
 		FileItem: suite.testFile,
diff --git a/git/branch/git_branch_list.go b/git/branch/git_branch_list.go
index 299c48e..4bdc2bb 100644
--- a/git/branch/git_branch_list.go
+++ b/git/branch/git_branch_list.go
@@ -14,10 +14,13 @@ type List interface {
 }
 
 type listBranch struct {
-	repo            *git2go.Repository
+	repo *git2go.Repository
+}
+
+var (
 	localBranchList []string
 	allBranchList   []string
-}
+)
 
 // ListBranches fetches all the branches from the target repository
 // The result will be returned as a struct with the current branch and all the available branches
@@ -39,8 +42,8 @@ func (l listBranch) ListBranches() (model.ListOfBranches, error) {
 
 	currentBranch = getCurrentBranchName(head)
 
-	l.allBranchList = append(l.allBranchList, currentBranch)
-	l.localBranchList = append(l.localBranchList, currentBranch)
+	allBranchList = append(allBranchList, currentBranch)
+	localBranchList = append(localBranchList, currentBranch)
 
 	localBranchIterator, itrErr := repo.NewBranchIterator(git2go.BranchAll)
 	if itrErr != nil {
@@ -56,8 +59,8 @@ func (l listBranch) ListBranches() (model.ListOfBranches, error) {
 
 	return model.ListOfBranches{
 		CurrentBranch: currentBranch,
-		BranchList:    l.localBranchList,
-		AllBranchList: l.allBranchList,
+		BranchList:    localBranchList,
+		AllBranchList: allBranchList,
 	}, nil
 }
 
@@ -81,8 +84,8 @@ func (l listBranch) classifyRemoteAndLocalBranches(branch *git2go.Branch, branch
 	if branch.IsRemote() && strings.Contains(branchName, "/") {
 		l.getRemoteBranchName(branchName, currentBranch)
 	} else {
-		l.allBranchList = append(l.allBranchList, branchName)
-		l.localBranchList = append(l.localBranchList, branchName)
+		allBranchList = append(allBranchList, branchName)
+		localBranchList = append(localBranchList, branchName)
 	}
 }
 
@@ -92,7 +95,7 @@ func (l listBranch) getRemoteBranchName(branchName string, currentBranch string)
 
 	if splitBranch != "HEAD" && splitBranch != currentBranch {
 		concatRemote := "remotes/" + strings.Join(splitString, "/")
-		l.allBranchList = append(l.allBranchList, concatRemote)
+		allBranchList = append(allBranchList, concatRemote)
 	}
 }
 
diff --git a/git/branch/git_branch_list_test.go b/git/branch/git_branch_list_test.go
index c61207b..8d2d7a5 100644
--- a/git/branch/git_branch_list_test.go
+++ b/git/branch/git_branch_list_test.go
@@ -5,12 +5,14 @@ import (
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/stretchr/testify/suite"
 	"os"
+	"path/filepath"
 	"testing"
 )
 
 type BranchListTestSuite struct {
 	suite.Suite
 	repo       *git2go.Repository
+	noHeadRepo *git2go.Repository
 	branchList List
 }
 
@@ -23,8 +25,35 @@ func (suite *BranchListTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
+	noHeadRepo, _ := git2go.InitRepository(noHeadPath, false)
+
 	suite.repo = r
+	suite.noHeadRepo = noHeadRepo
 	suite.branchList = NewBranchList(suite.repo)
 }
 
-func  (suite *BranchListTestSuite)
\ No newline at end of file
+func (suite *BranchListTestSuite) TestListBranches_WhenRepoHasBranches_ShouldReturnBranchList() {
+	branchList, err := suite.branchList.ListBranches()
+
+	suite.Nil(err)
+	suite.Greater(len(branchList.BranchList), 2)
+	suite.Greater(len(branchList.AllBranchList), 2)
+	suite.Equal("master", branchList.CurrentBranch)
+}
+
+func (suite *BranchListTestSuite) TestListBranches_WhenRepoIsNil_ShouldReturnError() {
+	suite.branchList = NewBranchList(nil)
+	branchList, err := suite.branchList.ListBranches()
+
+	suite.NotNil(err)
+	suite.Empty(branchList)
+}
+
+func (suite *BranchListTestSuite) TestListBranches_WhenRepoHasNoHead_ShouldReturnError() {
+	suite.branchList = NewBranchList(suite.noHeadRepo)
+	branchList, err := suite.branchList.ListBranches()
+
+	suite.NotNil(err)
+	suite.Empty(branchList)
+}
diff --git a/tests/git_branch_list_test.go b/tests/git_branch_list_test.go
deleted file mode 100644
index 8e6017f..0000000
--- a/tests/git_branch_list_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package tests
-
-import (
-	"github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/git/branch"
-	"github.com/stretchr/testify/assert"
-	"os"
-	"testing"
-)
-
-func TestGetBranchList(t *testing.T) {
-	b := make(chan branch.ListOfBranches)
-	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-
-	type args struct {
-		repo       *git.Repository
-		branchChan chan branch.ListOfBranches
-	}
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git branch list test case", args: struct {
-			repo       *git.Repository
-			branchChan chan branch.ListOfBranches
-		}{repo: r, branchChan: b}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			testObj := branch.NewBranchListInterface(tt.args.repo)
-
-			go testObj.ListBranches(tt.args.branchChan)
-			branchList := <-tt.args.branchChan
-
-			cBranch := branchList.CurrentBranch
-			aBranch := branchList.AllBranchList
-			bList := branchList.BranchList
-
-			assert.NotZero(t, len(cBranch))
-			assert.NotZero(t, len(aBranch))
-			assert.NotZero(t, len(bList))
-		})
-	}
-}
diff --git a/utils/array_generator.go.go b/utils/array_generator.go.go
new file mode 100644
index 0000000..5e4da57
--- /dev/null
+++ b/utils/array_generator.go.go
@@ -0,0 +1,11 @@
+package utils
+
+func GeneratePointerArrayFrom(array []string) []*string {
+	var pointerArray []*string
+
+	for _, element := range array {
+		pointerArray = append(pointerArray, &element)
+	}
+
+	return pointerArray
+}

From 56512e7d7463ea4161913f048437fc5adf2a8e83 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 3 Jul 2021 23:10:34 +0530
Subject: [PATCH 033/148] add new invalid repo test case for branch package

---
 .github/workflows/go-collab.yml        |  2 +-
 .github/workflows/go.yml               |  2 +-
 .gitignore                             |  1 +
 Makefile                               | 14 +++++++++++-
 build_scripts/clone_test_repo.sh       |  4 +++-
 git/branch/branch_validation_test.go   | 12 +++++------
 git/branch/git_branch_add_test.go      | 30 +++++++++++++++++++-------
 git/branch/git_branch_checkout_test.go | 18 ++++++++++++++--
 git/branch/git_branch_compare_test.go  | 10 +++++----
 git/branch/git_branch_delete_test.go   | 14 ++++++++++++
 git/branch/git_branch_list_test.go     |  2 +-
 11 files changed, 84 insertions(+), 25 deletions(-)

diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index f09cde1..41fb40f 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -46,7 +46,7 @@ jobs:
           sudo chown $(whoami) /usr/local/gitconvex/
           go generate
           $GITHUB_WORKSPACE/build_scripts/clone_test_repo.sh
-          go test ./... -count=1 -v
+          go test ./... -count=1 -cover
 
   gitconvex-build:
     needs:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 33054b5..1c17fb9 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -46,7 +46,7 @@ jobs:
           sudo chown $(whoami) /usr/local/gitconvex/
           go generate
           $GITHUB_WORKSPACE/build_scripts/clone_test_repo.sh
-          go test ./... -count=1 -v
+          go test ./... -count=1 -cover
 
   gitconvex-build:
     needs:
diff --git a/.gitignore b/.gitignore
index d3115bf..219510e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ gitconvex-test/
 
 env_config.json
 gitclient
+coverage.out
 /*.exe
 /*.dll
 gitconvex
diff --git a/Makefile b/Makefile
index 19b7b25..25aa698 100644
--- a/Makefile
+++ b/Makefile
@@ -34,8 +34,20 @@ test:
 	rm -rf $$GITCONVEX_TEST_REPO && \
  	go clean --cache && \
  	./build_scripts/clone_test_repo.sh && \
- 	go test ./... -count=1 && \
+ 	go test ./... -count=1 -cover -coverprofile=coverage.out && \
 	rm -rf $$GITCONVEX_TEST_REPO
 
+test-pretty:
+	export GITCONVEX_TEST_REPO="$(PWD)/gitconvex-test" && \
+	export GITCONVEX_DEFAULT_PATH="$(PWD)/gitconvex-test" && \
+	rm -rf $$GITCONVEX_TEST_REPO && \
+ 	go clean --cache && \
+ 	./build_scripts/clone_test_repo.sh && \
+ 	gotestsum ./... -count=1 -cover -coverprofile=coverage.out && \
+	rm -rf $$GITCONVEX_TEST_REPO
+
+show-coverage:
+	go tool cover -html=coverage.out
+
 start:
 	./dist/gitconvex
diff --git a/build_scripts/clone_test_repo.sh b/build_scripts/clone_test_repo.sh
index 4bea7db..f743c6a 100755
--- a/build_scripts/clone_test_repo.sh
+++ b/build_scripts/clone_test_repo.sh
@@ -1,3 +1,5 @@
 #!/bin/bash
 
-git clone https://github.com/neel1996/gitconvex-test.git $GITCONVEX_TEST_REPO
\ No newline at end of file
+git clone https://github.com/neel1996/gitconvex-test.git $GITCONVEX_TEST_REPO
+git init $GITCONVEX_TEST_REPO/no_head
+clear
\ No newline at end of file
diff --git a/git/branch/branch_validation_test.go b/git/branch/branch_validation_test.go
index 42f467a..15d1d0f 100644
--- a/git/branch/branch_validation_test.go
+++ b/git/branch/branch_validation_test.go
@@ -10,9 +10,9 @@ import (
 
 type BranchFieldValidationTestSuite struct {
 	suite.Suite
-	repo       *git2go.Repository
-	branchName string
-	validation Validation
+	repo        *git2go.Repository
+	branchNames []string
+	validation  Validation
 }
 
 func TestBranchFieldValidationTestSuite(t *testing.T) {
@@ -26,8 +26,8 @@ func (suite *BranchFieldValidationTestSuite) SetupTest() {
 	}
 
 	suite.repo = r
-	suite.branchName = "test_branch"
-	suite.validation = NewBranchFieldsValidation(suite.repo, suite.branchName)
+	suite.branchNames = []string{"test_branch_1", "test_branch_2"}
+	suite.validation = NewBranchFieldsValidation(suite.repo, suite.branchNames[0], suite.branchNames[1])
 }
 
 func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenAllFieldsAreValid_ShouldReturnNil() {
@@ -45,7 +45,7 @@ func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenRepoIs
 }
 
 func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenBranchNameIsEmpty_ShouldReturnError() {
-	suite.validation = NewBranchFieldsValidation(suite.repo, "")
+	suite.validation = NewBranchFieldsValidation(suite.repo, "", "")
 	err := suite.validation.ValidateBranchFields()
 
 	suite.NotNil(err)
diff --git a/git/branch/git_branch_add_test.go b/git/branch/git_branch_add_test.go
index 1d9196c..5381d19 100644
--- a/git/branch/git_branch_add_test.go
+++ b/git/branch/git_branch_add_test.go
@@ -5,13 +5,16 @@ import (
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/stretchr/testify/suite"
 	"os"
+	"path/filepath"
 	"testing"
 )
 
 type BranchAddTestSuite struct {
 	suite.Suite
-	repo      *git2go.Repository
-	branchAdd Add
+	repo       *git2go.Repository
+	noHeadRepo *git2go.Repository
+	branchName string
+	branchAdd  Add
 }
 
 func TestBranchAddTestSuite(t *testing.T) {
@@ -23,13 +26,18 @@ func (suite *BranchAddTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
 	suite.repo = r
-	suite.branchAdd = NewAddBranch(suite.repo, "test_1", false, nil)
+	suite.noHeadRepo = noHeadRepo
+	suite.branchName = "test_1"
+	suite.branchAdd = NewAddBranch(suite.repo, suite.branchName, false, nil)
 }
 
-func (suite *BranchAddTestSuite) TearDownTest() {
+func (suite *BranchAddTestSuite) TearDownSuite() {
 	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	NewDeleteBranch(r, "test_1").DeleteBranch()
+	_ = NewDeleteBranch(r, suite.branchName).DeleteBranch()
 }
 
 func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchAdditionSucceeds_ShouldReturnNil() {
@@ -46,8 +54,14 @@ func (suite *BranchAddTestSuite) TestAddBranch_WhenRepoIsNil_ShouldReturnError()
 }
 
 func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchNameIsEmpty_ShouldReturnError() {
-	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	suite.branchAdd = NewAddBranch(r, "", false, nil)
+	suite.branchAdd = NewAddBranch(suite.repo, "", false, nil)
+	branchAddError := suite.branchAdd.AddBranch()
+
+	suite.NotNil(branchAddError)
+}
+
+func (suite *BranchAddTestSuite) TestAddBranch_WhenHeadIsNil_ShouldReturnError() {
+	suite.branchAdd = NewAddBranch(suite.noHeadRepo, suite.branchName, false, nil)
 	branchAddError := suite.branchAdd.AddBranch()
 
 	suite.NotNil(branchAddError)
@@ -55,7 +69,7 @@ func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchNameIsEmpty_ShouldRetur
 
 func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchAdditionFails_ShouldReturnError() {
 	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	suite.branchAdd = NewAddBranch(r, "test_1", false, nil)
+	suite.branchAdd = NewAddBranch(r, "master", false, nil)
 
 	//Adding duplicate branches
 	_ = suite.branchAdd.AddBranch()
diff --git a/git/branch/git_branch_checkout_test.go b/git/branch/git_branch_checkout_test.go
index 6f6dae0..97d2866 100644
--- a/git/branch/git_branch_checkout_test.go
+++ b/git/branch/git_branch_checkout_test.go
@@ -5,6 +5,7 @@ import (
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/stretchr/testify/suite"
 	"os"
+	"path/filepath"
 	"testing"
 )
 
@@ -13,18 +14,24 @@ type BranchCheckoutTestSuite struct {
 	branchName     string
 	checkoutBranch Checkout
 	repo           *git2go.Repository
+	noHeadRepo     *git2go.Repository
 }
 
 func TestBranchCheckoutTestSuite(t *testing.T) {
 	suite.Run(t, new(BranchCheckoutTestSuite))
 }
 
-func (suite *BranchCheckoutTestSuite) SetupTest() {
+func (suite *BranchCheckoutTestSuite) SetupSuite() {
 	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	if err != nil {
 		fmt.Println(err)
 	}
+
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
 	suite.repo = r
+	suite.noHeadRepo = noHeadRepo
 	suite.branchName = "test_checkout"
 	addErr := NewAddBranch(suite.repo, suite.branchName, false, nil).AddBranch()
 	if addErr != nil {
@@ -39,7 +46,7 @@ func (suite *BranchCheckoutTestSuite) TearDownSuite() {
 	if err != nil {
 		return
 	}
-	NewDeleteBranch(suite.repo, suite.branchName).DeleteBranch()
+	_ = NewDeleteBranch(suite.repo, suite.branchName).DeleteBranch()
 }
 
 func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenBranchIsCheckedOut_ShouldReturnNil() {
@@ -71,6 +78,13 @@ func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenBranchNameIsEmpty_S
 	suite.Equal("branch name is empty", err.Error())
 }
 
+func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenRepoHasNoHead_ShouldReturnError() {
+	suite.checkoutBranch = NewBranchCheckout(suite.noHeadRepo, suite.branchName)
+	err := suite.checkoutBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
 func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenNonExistingBranchIsSelected_ShouldReturnError() {
 	suite.checkoutBranch = NewBranchCheckout(suite.repo, "no_exists")
 	err := suite.checkoutBranch.CheckoutBranch()
diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
index b346311..5658bf6 100644
--- a/git/branch/git_branch_compare_test.go
+++ b/git/branch/git_branch_compare_test.go
@@ -8,6 +8,7 @@ import (
 	"github.com/stretchr/testify/suite"
 	"io/ioutil"
 	"os"
+	"path/filepath"
 	"testing"
 	"time"
 )
@@ -31,7 +32,7 @@ func (suite *BranchCompareTestSuite) SetupSuite() {
 		fmt.Println(err)
 	}
 	suite.repo = r
-	suite.testFile = os.Getenv("GITCONVEX_TEST_REPO") + "/" + "compare_test.txt"
+	suite.testFile = os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "compare_test.txt"
 	suite.baseBranch = "master"
 	suite.compareBranch = "new_compare"
 	addErr := NewAddBranch(r, suite.compareBranch, false, nil).AddBranch()
@@ -53,7 +54,7 @@ func (suite *BranchCompareTestSuite) SetupTest() {
 }
 
 func (suite *BranchCompareTestSuite) TearDownSuite() {
-	checkoutErr := NewBranchCheckout(suite.repo, suite.baseBranch).CheckoutBranch()
+	checkoutErr := NewBranchCheckout(suite.repo, "master").CheckoutBranch()
 	if checkoutErr != nil {
 		logger.Log(checkoutErr.Error(), global.StatusError)
 		return
@@ -80,9 +81,10 @@ func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchesHaveDifferent
 		time.UTC,
 	).String()
 
-	suite.Len(compareResults, 1)
+	suite.NotNil(compareResults)
+	suite.NotZero(len(compareResults))
+	suite.NotZero(len(compareResults[0].Commits))
 
-	suite.Len(compareResults[0].Commits, 1)
 	suite.NotNil(*compareResults[0].Commits[0])
 	suite.NotEmpty(*compareResults[0].Commits[0].CommitMessage)
 	suite.Contains(timeString, compareResults[0].Date)
diff --git a/git/branch/git_branch_delete_test.go b/git/branch/git_branch_delete_test.go
index eab2459..6bce2d8 100644
--- a/git/branch/git_branch_delete_test.go
+++ b/git/branch/git_branch_delete_test.go
@@ -5,6 +5,7 @@ import (
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/stretchr/testify/suite"
 	"os"
+	"path/filepath"
 	"testing"
 )
 
@@ -13,6 +14,7 @@ type BranchDeleteTestSuite struct {
 	branchDelete Delete
 	branchName   string
 	repo         *git2go.Repository
+	noHeadRepo   *git2go.Repository
 }
 
 func TestBranchDeleteTestSuite(t *testing.T) {
@@ -24,7 +26,12 @@ func (suite *BranchDeleteTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
+
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
 	suite.repo = r
+	suite.noHeadRepo = noHeadRepo
 	suite.branchName = "delete_branch"
 	suite.branchDelete = NewDeleteBranch(suite.repo, suite.branchName)
 }
@@ -70,6 +77,13 @@ func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchNameIsEmpty_Shoul
 	suite.NotNil(err)
 }
 
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenRepoHasNoHead_ShouldReturnError() {
+	suite.branchDelete = NewDeleteBranch(suite.noHeadRepo, suite.branchName)
+	err := suite.branchDelete.DeleteBranch()
+
+	suite.NotNil(err)
+}
+
 func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchDoesNotExists_ShouldReturnError() {
 	suite.branchDelete = NewDeleteBranch(suite.repo, "no_exists")
 	err := suite.branchDelete.DeleteBranch()
diff --git a/git/branch/git_branch_list_test.go b/git/branch/git_branch_list_test.go
index 8d2d7a5..411d94c 100644
--- a/git/branch/git_branch_list_test.go
+++ b/git/branch/git_branch_list_test.go
@@ -26,7 +26,7 @@ func (suite *BranchListTestSuite) SetupTest() {
 		fmt.Println(err)
 	}
 	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
-	noHeadRepo, _ := git2go.InitRepository(noHeadPath, false)
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
 
 	suite.repo = r
 	suite.noHeadRepo = noHeadRepo

From 0242ea795f1e955af9b2ebc6506f67e017e2fbbc Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 4 Jul 2021 20:31:43 +0530
Subject: [PATCH 034/148] revise test suite for remote package

---
 build_scripts/clone_test_repo.sh          |  3 +-
 git/remote/git_remote_add.go              |  7 +---
 git/remote/git_remote_add_test.go         | 39 +++++++++++++++++---
 git/remote/git_remote_delete.go           | 15 ++------
 git/remote/git_remote_delete_test.go      | 27 ++++++++++++--
 git/remote/git_remote_edit.go             | 30 +++++++++++-----
 git/remote/git_remote_edit_test.go        | 44 ++++++++++++++++++++---
 git/remote/git_remote_list_test.go        | 22 ++++++++----
 git/remote/git_remote_remote_name.go      | 26 +++-----------
 git/remote/git_remote_remote_name_test.go | 18 +++++++++-
 git/remote/git_remote_url_data.go         | 14 +++-----
 git/remote/git_remote_url_data_test.go    | 22 +++++++++++-
 git/remote/remote_validation.go           | 22 ++++++++++--
 git/remote/remote_validation_test.go      | 14 +++++++-
 14 files changed, 219 insertions(+), 84 deletions(-)

diff --git a/build_scripts/clone_test_repo.sh b/build_scripts/clone_test_repo.sh
index f743c6a..fc5d826 100755
--- a/build_scripts/clone_test_repo.sh
+++ b/build_scripts/clone_test_repo.sh
@@ -1,5 +1,4 @@
 #!/bin/bash
 
 git clone https://github.com/neel1996/gitconvex-test.git $GITCONVEX_TEST_REPO
-git init $GITCONVEX_TEST_REPO/no_head
-clear
\ No newline at end of file
+git init $GITCONVEX_TEST_REPO/no_head
\ No newline at end of file
diff --git a/git/remote/git_remote_add.go b/git/remote/git_remote_add.go
index 365333e..15a8864 100644
--- a/git/remote/git_remote_add.go
+++ b/git/remote/git_remote_add.go
@@ -1,7 +1,6 @@
 package remote
 
 import (
-	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
@@ -35,15 +34,11 @@ func (a addRemote) NewRemote() error {
 }
 
 func (a addRemote) validateRemoteFields() error {
-	validationErr := NewRemoteValidation(a.repo).ValidateRemoteFields()
+	validationErr := NewRemoteValidation(a.repo, a.remoteName, a.remoteURL).ValidateRemoteFields()
 	if validationErr != nil {
 		return validationErr
 	}
 
-	if a.remoteURL == "" {
-		return errors.New("remote URL is empty")
-	}
-
 	return nil
 }
 
diff --git a/git/remote/git_remote_add_test.go b/git/remote/git_remote_add_test.go
index 6d5ec17..03ca827 100644
--- a/git/remote/git_remote_add_test.go
+++ b/git/remote/git_remote_add_test.go
@@ -3,6 +3,7 @@ package remote
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/global"
 	"github.com/stretchr/testify/suite"
 	"os"
 	"testing"
@@ -10,7 +11,10 @@ import (
 
 type RemoteAddTestSuite struct {
 	suite.Suite
-	addRemote Add
+	repo       *git2go.Repository
+	remoteName string
+	remoteUrl  string
+	addRemote  Add
 }
 
 func TestRemoteAddTestSuite(t *testing.T) {
@@ -22,7 +26,18 @@ func (suite *RemoteAddTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.addRemote = NewAddRemote(r, "new_origin", "https://github.com/neel1996/gitconvex-test.git")
+	suite.repo = r
+	suite.remoteName = "new_origin"
+	suite.remoteUrl = "https://github.com/neel1996/gitconvex-test.git"
+	suite.addRemote = NewAddRemote(suite.repo, suite.remoteName, suite.remoteUrl)
+}
+
+func (suite *RemoteAddTestSuite) TearDownSuite() {
+	err := NewDeleteRemote(suite.repo, suite.remoteName).DeleteRemote()
+	if err != nil {
+		logger.Log(err.Error(), global.StatusWarning)
+		return
+	}
 }
 
 func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenNewRemoteIsAdded_ShouldReturnNoError() {
@@ -31,8 +46,24 @@ func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenNewRemoteIsAdded_ShouldRet
 	suite.Nil(err)
 }
 
-func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRequiredFieldsAreEmpty_ShouldReturnError() {
-	suite.addRemote = NewAddRemote(nil, "", "")
+func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRepoIsNil_ShouldReturnError() {
+	suite.addRemote = NewAddRemote(nil, suite.remoteName, suite.remoteUrl)
+
+	err := suite.addRemote.NewRemote()
+
+	suite.NotNil(err)
+}
+
+func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteNameIsEmpty_ShouldReturnError() {
+	suite.addRemote = NewAddRemote(suite.repo, "", suite.remoteUrl)
+
+	err := suite.addRemote.NewRemote()
+
+	suite.NotNil(err)
+}
+
+func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteUrlIsEmpty_ShouldReturnError() {
+	suite.addRemote = NewAddRemote(suite.repo, suite.remoteName, "")
 
 	err := suite.addRemote.NewRemote()
 
diff --git a/git/remote/git_remote_delete.go b/git/remote/git_remote_delete.go
index 1821d8a..db43df8 100644
--- a/git/remote/git_remote_delete.go
+++ b/git/remote/git_remote_delete.go
@@ -1,7 +1,6 @@
 package remote
 
 import (
-	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
@@ -18,7 +17,8 @@ type deleteRemote struct {
 
 // DeleteRemote deletes the remote based on the specified remoteName
 func (d deleteRemote) DeleteRemote() error {
-	if validationError := NewRemoteValidation(d.repo).ValidateRemoteFields(); validationError != nil {
+	validationError := NewRemoteValidation(d.repo, d.remoteName).ValidateRemoteFields()
+	if validationError != nil {
 		return validationError
 	}
 
@@ -31,17 +31,6 @@ func (d deleteRemote) DeleteRemote() error {
 	return nil
 }
 
-func (d deleteRemote) validateRemoteFields() error {
-	if d.repo == nil {
-		return errors.New("repo is nil")
-	}
-
-	if d.remoteName == "" {
-		return errors.New("remote name cannot be empty")
-	}
-	return nil
-}
-
 func (d *deleteRemote) deleteSelectedRemote(remoteEntry string) error {
 	err := d.repo.Remotes.Delete(remoteEntry)
 	if err != nil {
diff --git a/git/remote/git_remote_delete_test.go b/git/remote/git_remote_delete_test.go
index 7a24790..5d590b0 100644
--- a/git/remote/git_remote_delete_test.go
+++ b/git/remote/git_remote_delete_test.go
@@ -10,6 +10,8 @@ import (
 
 type RemoteDeleteTestSuite struct {
 	suite.Suite
+	repo         *git2go.Repository
+	remoteName   string
 	deleteRemote Delete
 }
 
@@ -17,12 +19,23 @@ func TestRemoteDeleteTestSuite(t *testing.T) {
 	suite.Run(t, new(RemoteDeleteTestSuite))
 }
 
+func (suite *RemoteDeleteTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.remoteName = "new_origin"
+	_ = NewAddRemote(r, suite.remoteName, "remote://some_url").NewRemote()
+}
+
 func (suite *RemoteDeleteTestSuite) SetupTest() {
 	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.deleteRemote = NewDeleteRemote(r, "new_origin")
+	suite.repo = r
+	suite.remoteName = "new_origin"
+	suite.deleteRemote = NewDeleteRemote(r, suite.remoteName)
 }
 
 func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenNewRemoteIsDeleted_ShouldReturnNoError() {
@@ -31,8 +44,16 @@ func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenNewRemoteIsDeleted_S
 	suite.Nil(err)
 }
 
-func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRequiredFieldsAreEmpty_ShouldReturnError() {
-	suite.deleteRemote = NewDeleteRemote(nil, "")
+func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRepoIsNil_ShouldReturnError() {
+	suite.deleteRemote = NewDeleteRemote(nil, suite.remoteName)
+
+	err := suite.deleteRemote.DeleteRemote()
+
+	suite.NotNil(err)
+}
+
+func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteNameIsEmpty_ShouldReturnError() {
+	suite.deleteRemote = NewDeleteRemote(suite.repo, "")
 
 	err := suite.deleteRemote.DeleteRemote()
 
diff --git a/git/remote/git_remote_edit.go b/git/remote/git_remote_edit.go
index 6439335..7430593 100644
--- a/git/remote/git_remote_edit.go
+++ b/git/remote/git_remote_edit.go
@@ -2,6 +2,7 @@ package remote
 
 import (
 	"errors"
+	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
 )
@@ -19,7 +20,7 @@ type editRemote struct {
 func (e editRemote) EditRemote() error {
 	repo := e.repo
 
-	validationErr := e.validateRemoteFields()
+	validationErr := NewRemoteValidation(e.repo, e.remoteName, e.remoteURL).ValidateRemoteFields()
 	if validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return validationErr
@@ -33,6 +34,11 @@ func (e editRemote) EditRemote() error {
 		return listErr
 	}
 
+	if remoteAvailabilityErr := e.isRemotePresentInRepo(); remoteAvailabilityErr != nil {
+		logger.Log(remoteAvailabilityErr.Error(), global.StatusError)
+		return remoteAvailabilityErr
+	}
+
 	err := repo.Remotes.SetUrl(e.remoteName, e.remoteURL)
 	if err != nil {
 		logger.Log(err.Error(), global.StatusError)
@@ -43,16 +49,24 @@ func (e editRemote) EditRemote() error {
 	return nil
 }
 
-func (e editRemote) validateRemoteFields() error {
-	validationError := NewRemoteValidation(e.repo).ValidateRemoteFields()
-	if validationError != nil {
-		return validationError
+func (e editRemote) isRemotePresentInRepo() error {
+	var err error
+	remoteList := NewRemoteList(e.repo).GetAllRemotes()
+
+	if remoteList == nil {
+		err = errors.New("no remotes are present in the repo")
+		return err
 	}
 
-	if e.remoteName == "" || e.remoteURL == "" {
-		return errors.New("required field(s) are empty")
+	for _, remote := range remoteList {
+		if remote.RemoteName == e.remoteName {
+			logger.Log(fmt.Sprintf("Remote - %s is available in the repo", e.remoteName), global.StatusInfo)
+			return nil
+		}
 	}
-	return nil
+
+	err = errors.New(fmt.Sprintf("remote %s is not available in the repo", e.remoteName))
+	return err
 }
 
 func NewEditRemote(repo *git2go.Repository, remoteName string, remoteURL string) Edit {
diff --git a/git/remote/git_remote_edit_test.go b/git/remote/git_remote_edit_test.go
index e656b24..2a0a961 100644
--- a/git/remote/git_remote_edit_test.go
+++ b/git/remote/git_remote_edit_test.go
@@ -5,12 +5,16 @@ import (
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/stretchr/testify/suite"
 	"os"
+	"path/filepath"
 	"testing"
 )
 
 type RemoteEditTestSuite struct {
 	suite.Suite
 	repo       *git2go.Repository
+	noHeadRepo *git2go.Repository
+	remoteName string
+	remoteUrl  string
 	validation Validation
 	editRemote Edit
 }
@@ -24,8 +28,14 @@ func (suite *RemoteEditTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
 	suite.repo = r
-	suite.editRemote = NewEditRemote(r, "origin", "https://github.com/neel1996/gitconvex-test.git")
+	suite.noHeadRepo = noHeadRepo
+	suite.remoteName = "origin"
+	suite.remoteUrl = "https://github.com/neel1996/gitconvex-test.git"
+	suite.editRemote = NewEditRemote(r, suite.remoteName, suite.remoteUrl)
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsEdited_ShouldReturnNil() {
@@ -35,7 +45,7 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsEdited_ShouldReturn
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoIsNil_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(nil, "origin", "https://github.com/neel1996/gitconvex-test.git")
+	suite.editRemote = NewEditRemote(nil, suite.remoteName, suite.remoteUrl)
 
 	wantErr := suite.editRemote.EditRemote()
 
@@ -45,15 +55,39 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoIsNil_ShouldReturnError
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteCollectionIsNil_ShouldReturnError() {
 	suite.editRemote = NewEditRemote(&git2go.Repository{
 		Remotes: git2go.RemoteCollection{},
-	}, "origin", "https://github.com/neel1996/gitconvex-test.git")
+	}, suite.remoteName, suite.remoteUrl)
+
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.NotNil(wantErr)
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteNameIsEmpty_ShouldReturnError() {
+	suite.editRemote = NewEditRemote(suite.repo, "", suite.remoteUrl)
+
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.NotNil(wantErr)
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteUrlIsEmpty_ShouldReturnError() {
+	suite.editRemote = NewEditRemote(suite.repo, suite.remoteName, "")
+
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.NotNil(wantErr)
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoHasNoRemotes_ShouldReturnError() {
+	suite.editRemote = NewEditRemote(suite.noHeadRepo, suite.remoteName, suite.remoteUrl)
 
 	wantErr := suite.editRemote.EditRemote()
 
 	suite.NotNil(wantErr)
 }
 
-func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteEditFieldsAreEmpty_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(suite.repo, "", "")
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsNotPresent_ShouldReturnError() {
+	suite.editRemote = NewEditRemote(suite.repo, "no_exists_remote", suite.remoteUrl)
 
 	wantErr := suite.editRemote.EditRemote()
 
diff --git a/git/remote/git_remote_list_test.go b/git/remote/git_remote_list_test.go
index 2ff1903..4e86447 100644
--- a/git/remote/git_remote_list_test.go
+++ b/git/remote/git_remote_list_test.go
@@ -1,21 +1,33 @@
 package remote
 
 import (
+	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/stretchr/testify/suite"
 	"os"
+	"path/filepath"
 	"testing"
 )
 
 type ListRemoteTestSuite struct {
 	suite.Suite
+	repo       *git2go.Repository
+	noHeadRepo *git2go.Repository
 	listRemote List
 }
 
 func (suite *ListRemoteTestSuite) SetupTest() {
-	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	suite.listRemote = NewRemoteList(r)
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
+	suite.repo = r
+	suite.noHeadRepo = noHeadRepo
+	suite.listRemote = NewRemoteList(suite.repo)
 }
 
 func TestListRemoteTestSuite(t *testing.T) {
@@ -44,11 +56,7 @@ func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsNil_ShouldReturnNi
 }
 
 func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoHasNoRemotes_ShouldReturnNil() {
-	r := &git2go.Repository{
-		Remotes: git2go.RemoteCollection{},
-	}
-
-	suite.listRemote = NewRemoteList(r)
+	suite.listRemote = NewRemoteList(suite.noHeadRepo)
 
 	remoteList := suite.listRemote.GetAllRemotes()
 
diff --git a/git/remote/git_remote_remote_name.go b/git/remote/git_remote_remote_name.go
index 12908fd..f3a606c 100644
--- a/git/remote/git_remote_remote_name.go
+++ b/git/remote/git_remote_remote_name.go
@@ -1,7 +1,6 @@
 package remote
 
 import (
-	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
 )
@@ -23,37 +22,22 @@ func (r remoteName) GetRemoteNameWithUrl() string {
 		return ""
 	}
 
-	remoteList, remoteListError := repo.Remotes.List()
-	if remoteListError != nil {
-		logger.Log(remoteListError.Error(), global.StatusError)
+	remoteList := NewRemoteList(r.repo).GetAllRemotes()
+	if remoteList == nil {
+		logger.Log("repo has no remotes", global.StatusError)
 		return ""
 	}
 
 	for _, remote := range remoteList {
-		remoteEntry, remoteLookupErr := repo.Remotes.Lookup(remote)
-		if remoteLookupErr != nil {
-			logger.Log(remoteLookupErr.Error(), global.StatusError)
-			continue
-		}
-
-		isRemotePresent := r.isRemoteAvailable(remoteEntry, remote)
-		if isRemotePresent {
+		if r.remoteUrl == remote.RemoteURL {
 			logger.Log("Matching remote found for the URL", global.StatusInfo)
-			return remote
+			return remote.RemoteName
 		}
 	}
 
 	return ""
 }
 
-func (r remoteName) isRemoteAvailable(remoteEntry *git2go.Remote, remote string) bool {
-	if remoteEntry.Url() == r.remoteUrl {
-		logger.Log(fmt.Sprintf("Remote - %s found for the url - %s", remote, r.remoteUrl), global.StatusInfo)
-		return true
-	}
-	return false
-}
-
 func NewGetRemoteName(repo *git2go.Repository, remoteUrl string) Name {
 	return remoteName{
 		repo:      repo,
diff --git a/git/remote/git_remote_remote_name_test.go b/git/remote/git_remote_remote_name_test.go
index b63ed0c..8cd4502 100644
--- a/git/remote/git_remote_remote_name_test.go
+++ b/git/remote/git_remote_remote_name_test.go
@@ -5,6 +5,7 @@ import (
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/stretchr/testify/suite"
 	"os"
+	"path/filepath"
 	"testing"
 )
 
@@ -12,6 +13,7 @@ type GetRemoteNameTestSuite struct {
 	suite.Suite
 	getRemoteName Name
 	repo          *git2go.Repository
+	noHeadRepo    *git2go.Repository
 }
 
 func (suite *GetRemoteNameTestSuite) SetupTest() {
@@ -19,7 +21,12 @@ func (suite *GetRemoteNameTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.getRemoteName = NewGetRemoteName(r, "https://github.com/neel1996/gitconvex-test.git")
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
+	suite.repo = r
+	suite.noHeadRepo = noHeadRepo
+	suite.getRemoteName = NewGetRemoteName(suite.repo, "https://github.com/neel1996/gitconvex-test.git")
 }
 
 func TestGetRemoteNameTestSuite(t *testing.T) {
@@ -42,3 +49,12 @@ func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_W
 
 	suite.Equal(expectedRemote, actualRemote)
 }
+
+func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_WhenRepoHasNoRemotes() {
+	expectedRemote := ""
+	getRemoteName := NewGetRemoteName(suite.noHeadRepo, "https://github.com/neel1996/gitconvex-test.git")
+
+	actualRemote := getRemoteName.GetRemoteNameWithUrl()
+
+	suite.Equal(expectedRemote, actualRemote)
+}
diff --git a/git/remote/git_remote_url_data.go b/git/remote/git_remote_url_data.go
index 1f83197..8a45ed6 100644
--- a/git/remote/git_remote_url_data.go
+++ b/git/remote/git_remote_url_data.go
@@ -23,18 +23,14 @@ func (u listRemoteUrl) GetAllRemoteUrl() []*string {
 		return nil
 	}
 
-	remotes, listErr := repo.Remotes.List()
-	if listErr != nil {
-		logger.Log(listErr.Error(), global.StatusError)
+	remoteList := NewRemoteList(u.repo).GetAllRemotes()
+	if remoteList == nil {
+		logger.Log("repo has no remotes", global.StatusError)
 		return nil
 	}
 
-	for _, remoteName := range remotes {
-		remote, _ := repo.Remotes.Lookup(remoteName)
-		if remote != nil {
-			url := remote.Url()
-			remoteURL = append(remoteURL, &url)
-		}
+	for _, remote := range remoteList {
+		remoteURL = append(remoteURL, &remote.RemoteURL)
 	}
 
 	if len(remoteURL) == 0 {
diff --git a/git/remote/git_remote_url_data_test.go b/git/remote/git_remote_url_data_test.go
index 507d039..60a0860 100644
--- a/git/remote/git_remote_url_data_test.go
+++ b/git/remote/git_remote_url_data_test.go
@@ -1,14 +1,18 @@
 package remote
 
 import (
+	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/stretchr/testify/suite"
 	"os"
+	"path/filepath"
 	"testing"
 )
 
 type RemoteUrlDataTestSuite struct {
 	suite.Suite
+	repo          *git2go.Repository
+	noHeadRepo    *git2go.Repository
 	listRemoteUrl ListRemoteUrl
 }
 
@@ -17,7 +21,15 @@ func TestRemoteUrlDataTestSuite(t *testing.T) {
 }
 
 func (suite *RemoteUrlDataTestSuite) SetupTest() {
-	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
+	suite.repo = r
+	suite.noHeadRepo = noHeadRepo
 	suite.listRemoteUrl = NewRemoteUrlData(r)
 }
 
@@ -36,6 +48,14 @@ func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoIsNil_ShouldRet
 	suite.Nil(urlList)
 }
 
+func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoHasNoRemotes_ShouldReturnNil() {
+	suite.listRemoteUrl = NewRemoteUrlData(suite.noHeadRepo)
+
+	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
+
+	suite.Nil(urlList)
+}
+
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesAreNil_ShouldReturnNil() {
 	suite.listRemoteUrl = NewRemoteUrlData(&git2go.Repository{
 		Remotes: git2go.RemoteCollection{},
diff --git a/git/remote/remote_validation.go b/git/remote/remote_validation.go
index 09253f4..78f2868 100644
--- a/git/remote/remote_validation.go
+++ b/git/remote/remote_validation.go
@@ -10,7 +10,8 @@ type Validation interface {
 }
 
 type validation struct {
-	repo *git2go.Repository
+	repo         *git2go.Repository
+	remoteFields []string
 }
 
 func (v validation) ValidateRemoteFields() error {
@@ -24,6 +25,20 @@ func (v validation) ValidateRemoteFields() error {
 		return validateRemotesErr
 	}
 
+	fieldValidationErr := v.validateRemoteFields()
+	if fieldValidationErr != nil {
+		return fieldValidationErr
+	}
+
+	return nil
+}
+
+func (v validation) validateRemoteFields() error {
+	for _, field := range v.remoteFields {
+		if field == "" {
+			return errors.New("one or more remote fields are empty")
+		}
+	}
 	return nil
 }
 
@@ -43,8 +58,9 @@ func (v validation) validateRemoteCollection() error {
 	return nil
 }
 
-func NewRemoteValidation(repo *git2go.Repository) Validation {
+func NewRemoteValidation(repo *git2go.Repository, remoteFields ...string) Validation {
 	return validation{
-		repo: repo,
+		repo:         repo,
+		remoteFields: remoteFields,
 	}
 }
diff --git a/git/remote/remote_validation_test.go b/git/remote/remote_validation_test.go
index 358daf9..b1cf31d 100644
--- a/git/remote/remote_validation_test.go
+++ b/git/remote/remote_validation_test.go
@@ -11,6 +11,7 @@ import (
 type RemoteValidationTestSuite struct {
 	suite.Suite
 	repo                 *git2go.Repository
+	remoteFields         []string
 	validateRemoteFields Validation
 }
 
@@ -23,8 +24,10 @@ func (suite *RemoteValidationTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
+
+	suite.remoteFields = []string{"origin", "origin_1"}
 	suite.repo = r
-	suite.validateRemoteFields = NewRemoteValidation(suite.repo)
+	suite.validateRemoteFields = NewRemoteValidation(suite.repo, suite.remoteFields[0], suite.remoteFields[1])
 }
 
 func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenAllFieldsAreValid_ShouldReturnNil() {
@@ -54,3 +57,12 @@ func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRemoteColle
 	suite.NotNil(wantErr)
 	suite.Equal(wantErrorText, wantErr.Error())
 }
+
+func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRemoteFieldsAreEmpty_ShouldReturnError() {
+	suite.validateRemoteFields = NewRemoteValidation(suite.repo, "", "")
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields()
+	wantErrorText := "one or more remote fields are empty"
+
+	suite.NotNil(wantErr)
+	suite.Equal(wantErrorText, wantErr.Error())
+}

From 7f29e5a52ab5d234c7b7840b9ad5ebe65b204a41 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 4 Jul 2021 23:18:18 +0530
Subject: [PATCH 035/148] update CI test stage with make rule

---
 .github/workflows/go-collab.yml | 3 +--
 .github/workflows/go.yml        | 3 +--
 Makefile                        | 6 ++++++
 3 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index 41fb40f..1a4e10a 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -45,8 +45,7 @@ jobs:
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
           go generate
-          $GITHUB_WORKSPACE/build_scripts/clone_test_repo.sh
-          go test ./... -count=1 -cover
+          make test-ci
 
   gitconvex-build:
     needs:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 1c17fb9..4b84c0d 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -45,8 +45,7 @@ jobs:
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
           go generate
-          $GITHUB_WORKSPACE/build_scripts/clone_test_repo.sh
-          go test ./... -count=1 -cover
+          make test-ci
 
   gitconvex-build:
     needs:
diff --git a/Makefile b/Makefile
index 25aa698..d652218 100644
--- a/Makefile
+++ b/Makefile
@@ -46,6 +46,12 @@ test-pretty:
  	gotestsum ./... -count=1 -cover -coverprofile=coverage.out && \
 	rm -rf $$GITCONVEX_TEST_REPO
 
+test-ci:
+	go clean --cache && \
+    ./build_scripts/clone_test_repo.sh && \
+    go test ./... -count=1 -cover -coverprofile=coverage.out && \
+    rm -rf $$GITCONVEX_TEST_REPO
+
 show-coverage:
 	go tool cover -html=coverage.out
 

From 90a46aacf6b5adb303a8a768d1f6a21dd063716c Mon Sep 17 00:00:00 2001
From: test <test@test.com>
Date: Mon, 5 Jul 2021 23:57:49 +0530
Subject: [PATCH 036/148] dockerise ci test for consistency

---
 .dockerignore                         |  1 -
 .github/workflows/go-collab.yml       |  3 +--
 .github/workflows/go.yml              |  3 +--
 Makefile                              | 12 ++++++++++--
 Test.Dockerfile                       | 11 +++++++++++
 docker-compose.test.yaml              | 18 ++++++++++++++++++
 git/branch/git_branch_compare_test.go |  1 -
 7 files changed, 41 insertions(+), 8 deletions(-)
 create mode 100644 Test.Dockerfile
 create mode 100644 docker-compose.test.yaml

diff --git a/.dockerignore b/.dockerignore
index 8ba0791..9d8b3f9 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -2,7 +2,6 @@
 etc/
 lib/
 .github/
-tests/
 
 *.md
 gitconvex-k8s.yml
diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index 1a4e10a..3ea5599 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -44,8 +44,7 @@ jobs:
           git config --global user.name "${{ secrets.ACTION_USER_NAME }}" && git config --global user.email "${{ secrets.ACTION_USER_EMAIL }}"
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
-          go generate
-          make test-ci
+          make dockerise-test
 
   gitconvex-build:
     needs:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 4b84c0d..055dc0a 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -44,8 +44,7 @@ jobs:
           git config --global user.name "${{ secrets.ACTION_USER_NAME }}" && git config --global user.email "${{ secrets.ACTION_USER_EMAIL }}"
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
-          go generate
-          make test-ci
+          make dockerise-test
 
   gitconvex-build:
     needs:
diff --git a/Makefile b/Makefile
index d652218..8211286 100644
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,10 @@ build: clean build-ui bundle build-server
 	@echo "📬 Use ./dist/gitconvex to start Gitconvex on port 9001"
 	@echo "📬 Try ./dist/gitconvex --port PORT_NUMBER to run gitconvex on the desired port"
 
+git-testuser-setup:
+	git config user.name test
+	git config user.email test@test.com
+
 test:
 	export GITCONVEX_TEST_REPO="$(PWD)/gitconvex-test" && \
 	export GITCONVEX_DEFAULT_PATH="$(PWD)/gitconvex-test" && \
@@ -46,12 +50,16 @@ test-pretty:
  	gotestsum ./... -count=1 -cover -coverprofile=coverage.out && \
 	rm -rf $$GITCONVEX_TEST_REPO
 
-test-ci:
+test-ci: git-testuser-setup
+	go generate && \
 	go clean --cache && \
-    ./build_scripts/clone_test_repo.sh && \
+    sh ./build_scripts/clone_test_repo.sh && \
     go test ./... -count=1 -cover -coverprofile=coverage.out && \
     rm -rf $$GITCONVEX_TEST_REPO
 
+dockerise-test:
+	docker-compose -f docker-compose.test.yaml up
+
 show-coverage:
 	go tool cover -html=coverage.out
 
diff --git a/Test.Dockerfile b/Test.Dockerfile
new file mode 100644
index 0000000..b44c246
--- /dev/null
+++ b/Test.Dockerfile
@@ -0,0 +1,11 @@
+FROM golang:1.16.0-alpine
+
+WORKDIR /home/gitconvex
+
+COPY . .
+
+# Install required packages
+RUN apk update && \
+    apk add --update libgit2-dev libssh2-dev gcc make musl-dev git
+
+
diff --git a/docker-compose.test.yaml b/docker-compose.test.yaml
new file mode 100644
index 0000000..7d210cd
--- /dev/null
+++ b/docker-compose.test.yaml
@@ -0,0 +1,18 @@
+version: "3.3"
+
+networks:
+  gitconvex-test-network:
+
+services:
+  gitconvex-test:
+    build:
+      context: .
+      dockerfile: Test.Dockerfile
+    environment:
+      - GITCONVEX_TEST_REPO=/home/gitconvex/gitconvex-test
+      - GITCONVEX_DEFAULT_PATH=/home/gitconvex/gitconvex-test
+    networks:
+      - gitconvex-test-network
+    volumes:
+      - ./:/home/gitconvex
+    command: [ "make","test-ci" ]
\ No newline at end of file
diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
index 5658bf6..fd61763 100644
--- a/git/branch/git_branch_compare_test.go
+++ b/git/branch/git_branch_compare_test.go
@@ -33,7 +33,6 @@ func (suite *BranchCompareTestSuite) SetupSuite() {
 	}
 	suite.repo = r
 	suite.testFile = os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "compare_test.txt"
-	suite.baseBranch = "master"
 	suite.compareBranch = "new_compare"
 	addErr := NewAddBranch(r, suite.compareBranch, false, nil).AddBranch()
 	if addErr != nil {

From 22ba1747dec978c22e73084d2b4c5be0f85caf2d Mon Sep 17 00:00:00 2001
From: test <test@test.com>
Date: Tue, 6 Jul 2021 00:01:23 +0530
Subject: [PATCH 037/148] update git config stage to add global config

---
 Makefile | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index 8211286..5e63f1f 100644
--- a/Makefile
+++ b/Makefile
@@ -29,8 +29,8 @@ build: clean build-ui bundle build-server
 	@echo "📬 Try ./dist/gitconvex --port PORT_NUMBER to run gitconvex on the desired port"
 
 git-testuser-setup:
-	git config user.name test
-	git config user.email test@test.com
+	git config --global user.name "test"
+	git config --global user.email "test@test.com"
 
 test:
 	export GITCONVEX_TEST_REPO="$(PWD)/gitconvex-test" && \

From 02ca6eea34ea283043207683c621626389918255 Mon Sep 17 00:00:00 2001
From: test <test@test.com>
Date: Tue, 6 Jul 2021 09:58:16 +0530
Subject: [PATCH 038/148] add logging to check reason for test failure

---
 Makefile                              | 1 +
 git/branch/git_branch_compare_test.go | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/Makefile b/Makefile
index 5e63f1f..956f115 100644
--- a/Makefile
+++ b/Makefile
@@ -58,6 +58,7 @@ test-ci: git-testuser-setup
     rm -rf $$GITCONVEX_TEST_REPO
 
 dockerise-test:
+	rm -rf $$GITCONVEX_TEST_REPO && \
 	docker-compose -f docker-compose.test.yaml up
 
 show-coverage:
diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
index fd61763..b6449bc 100644
--- a/git/branch/git_branch_compare_test.go
+++ b/git/branch/git_branch_compare_test.go
@@ -80,6 +80,8 @@ func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchesHaveDifferent
 		time.UTC,
 	).String()
 
+	fmt.Println(compareResults)
+
 	suite.NotNil(compareResults)
 	suite.NotZero(len(compareResults))
 	suite.NotZero(len(compareResults[0].Commits))

From 8986e5e2af6abec215b9dc38e6b9d231c7f1e1ec Mon Sep 17 00:00:00 2001
From: test <test@test.com>
Date: Tue, 6 Jul 2021 22:45:40 +0530
Subject: [PATCH 039/148] revise test for branch compare

---
 Makefile                              |  1 +
 git/branch/git_branch_compare_test.go | 17 +----------------
 2 files changed, 2 insertions(+), 16 deletions(-)

diff --git a/Makefile b/Makefile
index 956f115..8b72576 100644
--- a/Makefile
+++ b/Makefile
@@ -59,6 +59,7 @@ test-ci: git-testuser-setup
 
 dockerise-test:
 	rm -rf $$GITCONVEX_TEST_REPO && \
+	docker-compose -f docker-compose.test.yaml build && \
 	docker-compose -f docker-compose.test.yaml up
 
 show-coverage:
diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
index b6449bc..149c7ca 100644
--- a/git/branch/git_branch_compare_test.go
+++ b/git/branch/git_branch_compare_test.go
@@ -10,7 +10,6 @@ import (
 	"os"
 	"path/filepath"
 	"testing"
-	"time"
 )
 
 type BranchCompareTestSuite struct {
@@ -68,27 +67,13 @@ func (suite *BranchCompareTestSuite) TearDownSuite() {
 func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchesHaveDifferentCommits_ShouldReturnDifference() {
 	compareResults := suite.branchCompare.CompareBranch()
 
-	currentTime := time.Now()
-	timeString := time.Date(
-		currentTime.Year(),
-		currentTime.Month(),
-		currentTime.Day(),
-		0,
-		0,
-		0,
-		0,
-		time.UTC,
-	).String()
-
-	fmt.Println(compareResults)
-
 	suite.NotNil(compareResults)
 	suite.NotZero(len(compareResults))
 	suite.NotZero(len(compareResults[0].Commits))
 
 	suite.NotNil(*compareResults[0].Commits[0])
 	suite.NotEmpty(*compareResults[0].Commits[0].CommitMessage)
-	suite.Contains(timeString, compareResults[0].Date)
+	suite.NotEmpty(compareResults[0].Date)
 	suite.Equal(1, len(compareResults[0].Commits))
 }
 

From 533ac467a5ad34cb02c218ac1ee5e8b2cf6397e8 Mon Sep 17 00:00:00 2001
From: Neel <47709856+neel1996@users.noreply.github.com>
Date: Wed, 7 Jul 2021 09:01:14 +0530
Subject: [PATCH 040/148] Update LIBGIT_NOTES.md

---
 LIBGIT_NOTES.md | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/LIBGIT_NOTES.md b/LIBGIT_NOTES.md
index 8838d5a..1946ee3 100644
--- a/LIBGIT_NOTES.md
+++ b/LIBGIT_NOTES.md
@@ -66,6 +66,8 @@ Following the above steps will make `libgit2` available as a shared library for
 
 #### For Linux (tested on Ubuntu 20.04)
 
+>If you have brew installed on your linux machine then you can follow the same instructions [mentioned below for MacOS](#for-macos) to setup libgit2 
+
 Make sure you have the following packages installed on your system
 
 - [cmake](https://cmake.org/download/)
@@ -73,7 +75,7 @@ Make sure you have the following packages installed on your system
 - [wget](https://www.gnu.org/software/wget/)
 - [gcc](https://gcc.gnu.org/)
 
-Make sure you have required rights for running the following commands. If any of these fail due to access errors, then
+Make sure you have required rights for running the following commands. If any of these fail due to access errors then
 try with `sudo`
 
 ```shell
@@ -110,11 +112,12 @@ The dependencies required to build and run gitconvex are readily available from
 
 Download and setup [brew](https://brew.sh/) to install all the required packages
 
+- [libssh2](https://formulae.brew.sh/formula/libssh2)
+  ```shell
+  brew install libssh2
+  ```
+  
 - [libgit2](https://formulae.brew.sh/formula/libgit2)
   ```shell
   brew install libgit2
   ```
-- [libssh2](https://formulae.brew.sh/formula/libssh2)
-  ```shell
-  brew install libssh2
-  ```
\ No newline at end of file

From 259524a54b6a947a82042c4d9b5a4fe17372dd85 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 6 Jul 2021 22:45:40 +0530
Subject: [PATCH 041/148] revise test for branch compare

---
 Makefile                              |  1 +
 git/branch/git_branch_compare_test.go | 17 +----------------
 2 files changed, 2 insertions(+), 16 deletions(-)

diff --git a/Makefile b/Makefile
index 956f115..8b72576 100644
--- a/Makefile
+++ b/Makefile
@@ -59,6 +59,7 @@ test-ci: git-testuser-setup
 
 dockerise-test:
 	rm -rf $$GITCONVEX_TEST_REPO && \
+	docker-compose -f docker-compose.test.yaml build && \
 	docker-compose -f docker-compose.test.yaml up
 
 show-coverage:
diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
index b6449bc..149c7ca 100644
--- a/git/branch/git_branch_compare_test.go
+++ b/git/branch/git_branch_compare_test.go
@@ -10,7 +10,6 @@ import (
 	"os"
 	"path/filepath"
 	"testing"
-	"time"
 )
 
 type BranchCompareTestSuite struct {
@@ -68,27 +67,13 @@ func (suite *BranchCompareTestSuite) TearDownSuite() {
 func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchesHaveDifferentCommits_ShouldReturnDifference() {
 	compareResults := suite.branchCompare.CompareBranch()
 
-	currentTime := time.Now()
-	timeString := time.Date(
-		currentTime.Year(),
-		currentTime.Month(),
-		currentTime.Day(),
-		0,
-		0,
-		0,
-		0,
-		time.UTC,
-	).String()
-
-	fmt.Println(compareResults)
-
 	suite.NotNil(compareResults)
 	suite.NotZero(len(compareResults))
 	suite.NotZero(len(compareResults[0].Commits))
 
 	suite.NotNil(*compareResults[0].Commits[0])
 	suite.NotEmpty(*compareResults[0].Commits[0].CommitMessage)
-	suite.Contains(timeString, compareResults[0].Date)
+	suite.NotEmpty(compareResults[0].Date)
 	suite.Equal(1, len(compareResults[0].Commits))
 }
 

From 8fc4b3f614ab1965441a86478325540c516613bd Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 7 Jul 2021 09:01:14 +0530
Subject: [PATCH 042/148] Update LIBGIT_NOTES.md

---
 LIBGIT_NOTES.md | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/LIBGIT_NOTES.md b/LIBGIT_NOTES.md
index 8838d5a..1946ee3 100644
--- a/LIBGIT_NOTES.md
+++ b/LIBGIT_NOTES.md
@@ -66,6 +66,8 @@ Following the above steps will make `libgit2` available as a shared library for
 
 #### For Linux (tested on Ubuntu 20.04)
 
+>If you have brew installed on your linux machine then you can follow the same instructions [mentioned below for MacOS](#for-macos) to setup libgit2 
+
 Make sure you have the following packages installed on your system
 
 - [cmake](https://cmake.org/download/)
@@ -73,7 +75,7 @@ Make sure you have the following packages installed on your system
 - [wget](https://www.gnu.org/software/wget/)
 - [gcc](https://gcc.gnu.org/)
 
-Make sure you have required rights for running the following commands. If any of these fail due to access errors, then
+Make sure you have required rights for running the following commands. If any of these fail due to access errors then
 try with `sudo`
 
 ```shell
@@ -110,11 +112,12 @@ The dependencies required to build and run gitconvex are readily available from
 
 Download and setup [brew](https://brew.sh/) to install all the required packages
 
+- [libssh2](https://formulae.brew.sh/formula/libssh2)
+  ```shell
+  brew install libssh2
+  ```
+  
 - [libgit2](https://formulae.brew.sh/formula/libgit2)
   ```shell
   brew install libgit2
   ```
-- [libssh2](https://formulae.brew.sh/formula/libssh2)
-  ```shell
-  brew install libssh2
-  ```
\ No newline at end of file

From 07c9fa060651758e28647fe7adf62ddfadfe2cd7 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 10 Jul 2021 23:59:21 +0530
Subject: [PATCH 043/148] refactor commit change api

---
 git/commit/commit.go                          |   1 +
 git/commit/git_commit_changes.go              | 157 ++++++++++++++++++
 .../git_commit_changes_test.go}               |   8 +-
 3 files changed, 162 insertions(+), 4 deletions(-)
 create mode 100644 git/commit/commit.go
 create mode 100644 git/commit/git_commit_changes.go
 rename git/{git_commit_changes.go => commit/git_commit_changes_test.go} (95%)

diff --git a/git/commit/commit.go b/git/commit/commit.go
new file mode 100644
index 0000000..5fd0c88
--- /dev/null
+++ b/git/commit/commit.go
@@ -0,0 +1 @@
+package commit
diff --git a/git/commit/git_commit_changes.go b/git/commit/git_commit_changes.go
new file mode 100644
index 0000000..2adba8d
--- /dev/null
+++ b/git/commit/git_commit_changes.go
@@ -0,0 +1,157 @@
+package commit
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/global"
+	"strings"
+)
+
+type Changes interface {
+	Add() error
+}
+
+type changes struct {
+	repo          *git2go.Repository
+	commitMessage []string
+}
+
+// Add commits the staged changes to the repo
+// Rewrites the repo index tree with the staged files to commit the changes
+func (c changes) Add() error {
+	var (
+		headCommit       *git2go.Commit
+		formattedMessage string
+		repo             = c.repo
+	)
+
+	signature, err := c.validateSignature(repo)
+	if err != nil {
+		return err
+	}
+
+	formattedMessage = c.formatCommitMessage()
+
+	headCommit, headCommitErr := c.currentHeadCommit()
+	if headCommitErr != nil {
+		logger.Log(headCommitErr.Error(), global.StatusError)
+		return headCommitErr
+	}
+
+	newTree, treeErr := c.treeForNewCommit(repo)
+	if treeErr != nil {
+		logger.Log(treeErr.Error(), global.StatusError)
+		return treeErr
+	}
+
+	newCommitId, newCommitIdErr := c.createNewCommit(headCommit, repo, signature, formattedMessage, newTree)
+	if newCommitIdErr != nil {
+		logger.Log(newCommitIdErr.Error(), global.StatusError)
+		return newCommitIdErr
+	}
+
+	setHeadErr := c.setHeadToNewCommit(repo, newCommitId, formattedMessage)
+	if setHeadErr != nil {
+		logger.Log(setHeadErr.Error(), global.StatusError)
+		return setHeadErr
+	}
+
+	logger.Log(fmt.Sprintf("New commit %s created", newCommitId.String()), global.StatusInfo)
+	return nil
+}
+
+func (c changes) validateSignature(repo *git2go.Repository) (*git2go.Signature, error) {
+	signature, signatureErr := repo.DefaultSignature()
+	if signatureErr != nil {
+		logger.Log(fmt.Sprintf("Error occurred while fetching repo signature -> %s", signatureErr.Error()), global.StatusError)
+		logger.Log("Setup you user name and email using `git config user.name and git config user.email`", global.StatusWarning)
+		return nil, signatureErr
+	}
+
+	return signature, nil
+}
+
+func (c changes) setHeadToNewCommit(repo *git2go.Repository, newCommitId *git2go.Oid, formattedMessage string) error {
+	if _, newCommitErr := repo.LookupCommit(newCommitId); newCommitErr != nil {
+		logger.Log(newCommitErr.Error(), global.StatusError)
+		return newCommitErr
+	}
+
+	head, headErr := repo.Head()
+	if headErr != nil {
+		logger.Log(headErr.Error(), global.StatusError)
+		return headErr
+	}
+
+	_, newRefErr := head.SetTarget(newCommitId, formattedMessage)
+	if newRefErr != nil {
+		logger.Log(newRefErr.Error(), global.StatusError)
+		return newRefErr
+	}
+
+	return nil
+}
+
+func (c changes) createNewCommit(headCommit *git2go.Commit, repo *git2go.Repository, signature *git2go.Signature, formattedMessage string, newTree *git2go.Tree) (*git2go.Oid, error) {
+	var (
+		newCommitId    *git2go.Oid
+		newCommitIdErr error
+	)
+
+	if headCommit == nil {
+		newCommitId, newCommitIdErr = repo.CreateCommit("HEAD", signature, signature, formattedMessage, newTree)
+	} else {
+		newCommitId, newCommitIdErr = repo.CreateCommit("HEAD", signature, signature, formattedMessage, newTree, headCommit)
+	}
+
+	return newCommitId, newCommitIdErr
+}
+
+func (c changes) treeForNewCommit(repo *git2go.Repository) (*git2go.Tree, error) {
+	treeId, indexErr := c.updateRepoIndex()
+	if indexErr != nil {
+		logger.Log(indexErr.Error(), global.StatusError)
+		return nil, indexErr
+	}
+
+	newTree, newTreeErr := repo.LookupTree(treeId)
+	if newTreeErr != nil {
+		logger.Log(newTreeErr.Error(), global.StatusError)
+		return nil, newTreeErr
+	}
+	return newTree, nil
+}
+
+func (c changes) updateRepoIndex() (*git2go.Oid, error) {
+	repoIndex, indexErr := c.repo.Index()
+	if indexErr != nil {
+		return nil, indexErr
+	}
+
+	return repoIndex.WriteTree()
+}
+
+func (c changes) currentHeadCommit() (*git2go.Commit, error) {
+	head, headErr := c.repo.Head()
+	if headErr != nil {
+		logger.Log("Repo has no HEAD. Proceeding with a NIL HEAD", global.StatusWarning)
+		return nil, nil
+	}
+
+	return c.repo.LookupCommit(head.Target())
+}
+
+func (c changes) formatCommitMessage() string {
+	if len(c.commitMessage) > 0 {
+		return strings.Join(c.commitMessage, "\n")
+	}
+
+	return strings.Join(c.commitMessage, "")
+}
+
+func NewCommitChanges(repo *git2go.Repository, message []string) Changes {
+	return changes{
+		repo:          repo,
+		commitMessage: message,
+	}
+}
diff --git a/git/git_commit_changes.go b/git/commit/git_commit_changes_test.go
similarity index 95%
rename from git/git_commit_changes.go
rename to git/commit/git_commit_changes_test.go
index f6fb1c3..ea1c17b 100644
--- a/git/git_commit_changes.go
+++ b/git/commit/git_commit_changes_test.go
@@ -1,4 +1,4 @@
-package git
+package commit
 
 import (
 	"fmt"
@@ -8,11 +8,11 @@ import (
 	"strings"
 )
 
-type CommitInterface interface {
+type Changes interface {
 	CommitChanges() string
 }
 
-type CommitStruct struct {
+type changes struct {
 	Repo          *git2go.Repository
 	CommitMessage string
 	RepoPath      string
@@ -29,7 +29,7 @@ func checkCommitError(err error) bool {
 
 // CommitChanges commits the staged changes to the repo
 // Rewrites the repo index tree with the staged files to commit the changes
-func (c CommitStruct) CommitChanges() string {
+func (c CommitStruct) AddChanges() string {
 	var errStatus bool
 	var headCommit *git2go.Commit
 

From 30f71120a139f106251e49c59286ca1a95a7f7a8 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 12 Jul 2021 23:52:39 +0530
Subject: [PATCH 044/148] add common package interface for commit

---
 git/commit/commit.go                          |  23 +++
 go.sum                                        |   6 +
 graph/generated/generated.go                  | 158 +++++++++---------
 graph/schema.graphqls                         |   2 +-
 graph/schema.resolvers.go                     |  26 +--
 ...ray_generator.go.go => array_generator.go} |  10 ++
 6 files changed, 134 insertions(+), 91 deletions(-)
 rename utils/{array_generator.go.go => array_generator.go} (51%)

diff --git a/git/commit/commit.go b/git/commit/commit.go
index 5fd0c88..d09499d 100644
--- a/git/commit/commit.go
+++ b/git/commit/commit.go
@@ -1 +1,24 @@
 package commit
+
+import "github.com/neel1996/gitconvex/global"
+
+var logger global.Logger
+
+type Commit interface {
+	GitCommitChange() (string, error)
+}
+
+type Operation struct {
+	Changes Changes
+}
+
+func (c Operation) GitCommitChange() (string, error) {
+	err := c.Changes.Add()
+
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return global.CommitChangeError, err
+	}
+
+	return global.CommitChangeSuccess, nil
+}
diff --git a/go.sum b/go.sum
index f0dd038..050cf22 100644
--- a/go.sum
+++ b/go.sum
@@ -8,6 +8,7 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNg
 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
 github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
 github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -44,16 +45,19 @@ github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047 h1:zCoDWFD5
 github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
 github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
 github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
 github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
+github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
 github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
@@ -64,6 +68,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
 github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
 github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
 github.com/vektah/gqlparser/v2 v2.1.0 h1:uiKJ+T5HMGGQM2kRKQ8Pxw8+Zq9qhhZhz/lieYvCMns=
@@ -89,6 +94,7 @@ golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXR
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589 h1:rjUrONFu4kLchcZTfp3/96bR8bW8dIa8uz3cR5n0cgM=
 golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/graph/generated/generated.go b/graph/generated/generated.go
index cba9747..16b6027 100644
--- a/graph/generated/generated.go
+++ b/graph/generated/generated.go
@@ -97,7 +97,7 @@ type ComplexityRoot struct {
 		AddRemote           func(childComplexity int, repoID string, remoteName string, remoteURL string) int
 		AddRepo             func(childComplexity int, repoName string, repoPath string, cloneSwitch bool, repoURL *string, initSwitch bool, authOption string, sshKeyPath *string, userName *string, password *string) int
 		CheckoutBranch      func(childComplexity int, repoID string, branchName string) int
-		CommitChanges       func(childComplexity int, repoID string, commitMessage string) int
+		CommitChanges       func(childComplexity int, repoID string, commitMessage []*string) int
 		DeleteBranch        func(childComplexity int, repoID string, branchName string, forceFlag bool) int
 		DeleteRemote        func(childComplexity int, repoID string, remoteName string) int
 		DeleteRepo          func(childComplexity int, repoID string) int
@@ -206,7 +206,7 @@ type MutationResolver interface {
 	RemoveStagedItem(ctx context.Context, repoID string, item string) (string, error)
 	RemoveAllStagedItem(ctx context.Context, repoID string) (string, error)
 	StageAllItems(ctx context.Context, repoID string) (string, error)
-	CommitChanges(ctx context.Context, repoID string, commitMessage string) (string, error)
+	CommitChanges(ctx context.Context, repoID string, commitMessage []*string) (string, error)
 	PushToRemote(ctx context.Context, repoID string, remoteHost string, branch string) (string, error)
 	SettingsEditPort(ctx context.Context, newPort string) (string, error)
 	UpdateRepoDataFile(ctx context.Context, newDbFile string) (string, error)
@@ -482,7 +482,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 			return 0, false
 		}
 
-		return e.complexity.Mutation.CommitChanges(childComplexity, args["repoId"].(string), args["commitMessage"].(string)), true
+		return e.complexity.Mutation.CommitChanges(childComplexity, args["repoId"].(string), args["commitMessage"].([]*string)), true
 
 	case "Mutation.deleteBranch":
 		if e.complexity.Mutation.DeleteBranch == nil {
@@ -1501,7 +1501,7 @@ type Mutation {
         "The UUID of the repo. It will be available in the JSON data file"
         repoId: String!,
         "The message for the commit"
-        commitMessage: String!
+        commitMessage: [String]!
     ): String!
 
     "Pushes the commits to the remote"
@@ -1756,10 +1756,10 @@ func (ec *executionContext) field_Mutation_commitChanges_args(ctx context.Contex
 		}
 	}
 	args["repoId"] = arg0
-	var arg1 string
+	var arg1 []*string
 	if tmp, ok := rawArgs["commitMessage"]; ok {
 		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("commitMessage"))
-		arg1, err = ec.unmarshalNString2string(ctx, tmp)
+		arg1, err = ec.unmarshalNString2ᚕᚖstring(ctx, tmp)
 		if err != nil {
 			return nil, err
 		}
@@ -2865,7 +2865,7 @@ func (ec *executionContext) _GitCommitLogResults_commits(ctx context.Context, fi
 	}
 	res := resTmp.([]*model.GitCommits)
 	fc.Result = res
-	return ec.marshalOgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
+	return ec.marshalOgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _GitFolderContentResults_trackedFiles(ctx context.Context, field graphql.CollectedField, obj *model.GitFolderContentResults) (ret graphql.Marshaler) {
@@ -3335,7 +3335,7 @@ func (ec *executionContext) _Mutation_addRepo(ctx context.Context, field graphql
 	}
 	res := resTmp.(*model.AddRepoParams)
 	fc.Result = res
-	return ec.marshalNAddRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐAddRepoParams(ctx, field.Selections, res)
+	return ec.marshalNAddRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐAddRepoParams(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_addBranch(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -3461,7 +3461,7 @@ func (ec *executionContext) _Mutation_deleteBranch(ctx context.Context, field gr
 	}
 	res := resTmp.(*model.BranchDeleteStatus)
 	fc.Result = res
-	return ec.marshalNBranchDeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchDeleteStatus(ctx, field.Selections, res)
+	return ec.marshalNBranchDeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchDeleteStatus(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_fetchFromRemote(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -3503,7 +3503,7 @@ func (ec *executionContext) _Mutation_fetchFromRemote(ctx context.Context, field
 	}
 	res := resTmp.(*model.FetchResult)
 	fc.Result = res
-	return ec.marshalNFetchResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFetchResult(ctx, field.Selections, res)
+	return ec.marshalNFetchResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFetchResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_pullFromRemote(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -3545,7 +3545,7 @@ func (ec *executionContext) _Mutation_pullFromRemote(ctx context.Context, field
 	}
 	res := resTmp.(*model.PullResult)
 	fc.Result = res
-	return ec.marshalNPullResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐPullResult(ctx, field.Selections, res)
+	return ec.marshalNPullResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐPullResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_stageItem(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -3741,7 +3741,7 @@ func (ec *executionContext) _Mutation_commitChanges(ctx context.Context, field g
 	fc.Args = args
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.Mutation().CommitChanges(rctx, args["repoId"].(string), args["commitMessage"].(string))
+		return ec.resolvers.Mutation().CommitChanges(rctx, args["repoId"].(string), args["commitMessage"].([]*string))
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -3923,7 +3923,7 @@ func (ec *executionContext) _Mutation_deleteRepo(ctx context.Context, field grap
 	}
 	res := resTmp.(*model.DeleteStatus)
 	fc.Result = res
-	return ec.marshalNdeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐDeleteStatus(ctx, field.Selections, res)
+	return ec.marshalNdeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐDeleteStatus(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_updateRepoName(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4007,7 +4007,7 @@ func (ec *executionContext) _Mutation_addRemote(ctx context.Context, field graph
 	}
 	res := resTmp.(*model.RemoteMutationResult)
 	fc.Result = res
-	return ec.marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteMutationResult(ctx, field.Selections, res)
+	return ec.marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteMutationResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_deleteRemote(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4049,7 +4049,7 @@ func (ec *executionContext) _Mutation_deleteRemote(ctx context.Context, field gr
 	}
 	res := resTmp.(*model.RemoteMutationResult)
 	fc.Result = res
-	return ec.marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteMutationResult(ctx, field.Selections, res)
+	return ec.marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteMutationResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_editRemote(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4091,7 +4091,7 @@ func (ec *executionContext) _Mutation_editRemote(ctx context.Context, field grap
 	}
 	res := resTmp.(*model.RemoteMutationResult)
 	fc.Result = res
-	return ec.marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteMutationResult(ctx, field.Selections, res)
+	return ec.marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteMutationResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _PullResult_status(ctx context.Context, field graphql.CollectedField, obj *model.PullResult) (ret graphql.Marshaler) {
@@ -4196,7 +4196,7 @@ func (ec *executionContext) _Query_healthCheck(ctx context.Context, field graphq
 	}
 	res := resTmp.(*model.HealthCheckParams)
 	fc.Result = res
-	return ec.marshalNHealthCheckParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐHealthCheckParams(ctx, field.Selections, res)
+	return ec.marshalNHealthCheckParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐHealthCheckParams(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_fetchRepo(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4231,7 +4231,7 @@ func (ec *executionContext) _Query_fetchRepo(ctx context.Context, field graphql.
 	}
 	res := resTmp.(*model.FetchRepoParams)
 	fc.Result = res
-	return ec.marshalNFetchRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFetchRepoParams(ctx, field.Selections, res)
+	return ec.marshalNFetchRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFetchRepoParams(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitRepoStatus(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4273,7 +4273,7 @@ func (ec *executionContext) _Query_gitRepoStatus(ctx context.Context, field grap
 	}
 	res := resTmp.(*model.GitRepoStatusResults)
 	fc.Result = res
-	return ec.marshalNGitRepoStatusResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitRepoStatusResults(ctx, field.Selections, res)
+	return ec.marshalNGitRepoStatusResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitRepoStatusResults(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitFolderContent(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4315,7 +4315,7 @@ func (ec *executionContext) _Query_gitFolderContent(ctx context.Context, field g
 	}
 	res := resTmp.(*model.GitFolderContentResults)
 	fc.Result = res
-	return ec.marshalNGitFolderContentResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitFolderContentResults(ctx, field.Selections, res)
+	return ec.marshalNGitFolderContentResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitFolderContentResults(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitCommitLogs(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4357,7 +4357,7 @@ func (ec *executionContext) _Query_gitCommitLogs(ctx context.Context, field grap
 	}
 	res := resTmp.(*model.GitCommitLogResults)
 	fc.Result = res
-	return ec.marshalNGitCommitLogResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitLogResults(ctx, field.Selections, res)
+	return ec.marshalNGitCommitLogResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitLogResults(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitCommitFiles(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4399,7 +4399,7 @@ func (ec *executionContext) _Query_gitCommitFiles(ctx context.Context, field gra
 	}
 	res := resTmp.([]*model.GitCommitFileResult)
 	fc.Result = res
-	return ec.marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitFileResult(ctx, field.Selections, res)
+	return ec.marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitFileResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_searchCommitLogs(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4441,7 +4441,7 @@ func (ec *executionContext) _Query_searchCommitLogs(ctx context.Context, field g
 	}
 	res := resTmp.([]*model.GitCommits)
 	fc.Result = res
-	return ec.marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
+	return ec.marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_codeFileDetails(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4483,7 +4483,7 @@ func (ec *executionContext) _Query_codeFileDetails(ctx context.Context, field gr
 	}
 	res := resTmp.(*model.CodeFileType)
 	fc.Result = res
-	return ec.marshalNcodeFileType2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐCodeFileType(ctx, field.Selections, res)
+	return ec.marshalNcodeFileType2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐCodeFileType(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitChanges(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4525,7 +4525,7 @@ func (ec *executionContext) _Query_gitChanges(ctx context.Context, field graphql
 	}
 	res := resTmp.(*model.GitChangeResults)
 	fc.Result = res
-	return ec.marshalNgitChangeResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitChangeResults(ctx, field.Selections, res)
+	return ec.marshalNgitChangeResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitChangeResults(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitUnPushedCommits(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4567,7 +4567,7 @@ func (ec *executionContext) _Query_gitUnPushedCommits(ctx context.Context, field
 	}
 	res := resTmp.(*model.UnPushedCommitResult)
 	fc.Result = res
-	return ec.marshalNUnPushedCommitResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐUnPushedCommitResult(ctx, field.Selections, res)
+	return ec.marshalNUnPushedCommitResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐUnPushedCommitResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitFileLineChanges(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4609,7 +4609,7 @@ func (ec *executionContext) _Query_gitFileLineChanges(ctx context.Context, field
 	}
 	res := resTmp.(*model.FileLineChangeResult)
 	fc.Result = res
-	return ec.marshalNfileLineChangeResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFileLineChangeResult(ctx, field.Selections, res)
+	return ec.marshalNfileLineChangeResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFileLineChangeResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_settingsData(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4644,7 +4644,7 @@ func (ec *executionContext) _Query_settingsData(ctx context.Context, field graph
 	}
 	res := resTmp.(*model.SettingsDataResults)
 	fc.Result = res
-	return ec.marshalNsettingsDataResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐSettingsDataResults(ctx, field.Selections, res)
+	return ec.marshalNsettingsDataResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐSettingsDataResults(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_commitCompare(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4686,7 +4686,7 @@ func (ec *executionContext) _Query_commitCompare(ctx context.Context, field grap
 	}
 	res := resTmp.([]*model.GitCommitFileResult)
 	fc.Result = res
-	return ec.marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitFileResult(ctx, field.Selections, res)
+	return ec.marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitFileResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_branchCompare(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4728,7 +4728,7 @@ func (ec *executionContext) _Query_branchCompare(ctx context.Context, field grap
 	}
 	res := resTmp.([]*model.BranchCompareResults)
 	fc.Result = res
-	return ec.marshalNbranchCompareResults2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchCompareResults(ctx, field.Selections, res)
+	return ec.marshalNbranchCompareResults2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchCompareResults(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_getRemote(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4770,7 +4770,7 @@ func (ec *executionContext) _Query_getRemote(ctx context.Context, field graphql.
 	}
 	res := resTmp.([]*model.RemoteDetails)
 	fc.Result = res
-	return ec.marshalNremoteDetails2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteDetails(ctx, field.Selections, res)
+	return ec.marshalNremoteDetails2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteDetails(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4911,7 +4911,7 @@ func (ec *executionContext) _UnPushedCommitResult_gitCommits(ctx context.Context
 	}
 	res := resTmp.([]*model.GitCommits)
 	fc.Result = res
-	return ec.marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
+	return ec.marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {
@@ -6064,7 +6064,7 @@ func (ec *executionContext) _branchCompareResults_commits(ctx context.Context, f
 	}
 	res := resTmp.([]*model.GitCommits)
 	fc.Result = res
-	return ec.marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
+	return ec.marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _codeFileType_fileData(ctx context.Context, field graphql.CollectedField, obj *model.CodeFileType) (ret graphql.Marshaler) {
@@ -8017,11 +8017,11 @@ func (ec *executionContext) _settingsDataResults(ctx context.Context, sel ast.Se
 
 // region    ***************************** type.gotpl *****************************
 
-func (ec *executionContext) marshalNAddRepoParams2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐAddRepoParams(ctx context.Context, sel ast.SelectionSet, v model.AddRepoParams) graphql.Marshaler {
+func (ec *executionContext) marshalNAddRepoParams2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐAddRepoParams(ctx context.Context, sel ast.SelectionSet, v model.AddRepoParams) graphql.Marshaler {
 	return ec._AddRepoParams(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNAddRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐAddRepoParams(ctx context.Context, sel ast.SelectionSet, v *model.AddRepoParams) graphql.Marshaler {
+func (ec *executionContext) marshalNAddRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐAddRepoParams(ctx context.Context, sel ast.SelectionSet, v *model.AddRepoParams) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8046,11 +8046,11 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se
 	return res
 }
 
-func (ec *executionContext) marshalNBranchDeleteStatus2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchDeleteStatus(ctx context.Context, sel ast.SelectionSet, v model.BranchDeleteStatus) graphql.Marshaler {
+func (ec *executionContext) marshalNBranchDeleteStatus2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchDeleteStatus(ctx context.Context, sel ast.SelectionSet, v model.BranchDeleteStatus) graphql.Marshaler {
 	return ec._BranchDeleteStatus(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNBranchDeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchDeleteStatus(ctx context.Context, sel ast.SelectionSet, v *model.BranchDeleteStatus) graphql.Marshaler {
+func (ec *executionContext) marshalNBranchDeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchDeleteStatus(ctx context.Context, sel ast.SelectionSet, v *model.BranchDeleteStatus) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8060,11 +8060,11 @@ func (ec *executionContext) marshalNBranchDeleteStatus2ᚖgithubᚗcomᚋneel199
 	return ec._BranchDeleteStatus(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNFetchRepoParams2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFetchRepoParams(ctx context.Context, sel ast.SelectionSet, v model.FetchRepoParams) graphql.Marshaler {
+func (ec *executionContext) marshalNFetchRepoParams2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFetchRepoParams(ctx context.Context, sel ast.SelectionSet, v model.FetchRepoParams) graphql.Marshaler {
 	return ec._FetchRepoParams(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNFetchRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFetchRepoParams(ctx context.Context, sel ast.SelectionSet, v *model.FetchRepoParams) graphql.Marshaler {
+func (ec *executionContext) marshalNFetchRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFetchRepoParams(ctx context.Context, sel ast.SelectionSet, v *model.FetchRepoParams) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8074,11 +8074,11 @@ func (ec *executionContext) marshalNFetchRepoParams2ᚖgithubᚗcomᚋneel1996
 	return ec._FetchRepoParams(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNFetchResult2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFetchResult(ctx context.Context, sel ast.SelectionSet, v model.FetchResult) graphql.Marshaler {
+func (ec *executionContext) marshalNFetchResult2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFetchResult(ctx context.Context, sel ast.SelectionSet, v model.FetchResult) graphql.Marshaler {
 	return ec._FetchResult(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNFetchResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFetchResult(ctx context.Context, sel ast.SelectionSet, v *model.FetchResult) graphql.Marshaler {
+func (ec *executionContext) marshalNFetchResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFetchResult(ctx context.Context, sel ast.SelectionSet, v *model.FetchResult) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8088,11 +8088,11 @@ func (ec *executionContext) marshalNFetchResult2ᚖgithubᚗcomᚋneel1996ᚋgit
 	return ec._FetchResult(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNGitCommitLogResults2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitLogResults(ctx context.Context, sel ast.SelectionSet, v model.GitCommitLogResults) graphql.Marshaler {
+func (ec *executionContext) marshalNGitCommitLogResults2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitLogResults(ctx context.Context, sel ast.SelectionSet, v model.GitCommitLogResults) graphql.Marshaler {
 	return ec._GitCommitLogResults(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNGitCommitLogResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitLogResults(ctx context.Context, sel ast.SelectionSet, v *model.GitCommitLogResults) graphql.Marshaler {
+func (ec *executionContext) marshalNGitCommitLogResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitLogResults(ctx context.Context, sel ast.SelectionSet, v *model.GitCommitLogResults) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8102,11 +8102,11 @@ func (ec *executionContext) marshalNGitCommitLogResults2ᚖgithubᚗcomᚋneel19
 	return ec._GitCommitLogResults(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNGitFolderContentResults2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitFolderContentResults(ctx context.Context, sel ast.SelectionSet, v model.GitFolderContentResults) graphql.Marshaler {
+func (ec *executionContext) marshalNGitFolderContentResults2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitFolderContentResults(ctx context.Context, sel ast.SelectionSet, v model.GitFolderContentResults) graphql.Marshaler {
 	return ec._GitFolderContentResults(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNGitFolderContentResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitFolderContentResults(ctx context.Context, sel ast.SelectionSet, v *model.GitFolderContentResults) graphql.Marshaler {
+func (ec *executionContext) marshalNGitFolderContentResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitFolderContentResults(ctx context.Context, sel ast.SelectionSet, v *model.GitFolderContentResults) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8116,11 +8116,11 @@ func (ec *executionContext) marshalNGitFolderContentResults2ᚖgithubᚗcomᚋne
 	return ec._GitFolderContentResults(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNGitRepoStatusResults2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitRepoStatusResults(ctx context.Context, sel ast.SelectionSet, v model.GitRepoStatusResults) graphql.Marshaler {
+func (ec *executionContext) marshalNGitRepoStatusResults2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitRepoStatusResults(ctx context.Context, sel ast.SelectionSet, v model.GitRepoStatusResults) graphql.Marshaler {
 	return ec._GitRepoStatusResults(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNGitRepoStatusResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitRepoStatusResults(ctx context.Context, sel ast.SelectionSet, v *model.GitRepoStatusResults) graphql.Marshaler {
+func (ec *executionContext) marshalNGitRepoStatusResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitRepoStatusResults(ctx context.Context, sel ast.SelectionSet, v *model.GitRepoStatusResults) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8130,11 +8130,11 @@ func (ec *executionContext) marshalNGitRepoStatusResults2ᚖgithubᚗcomᚋneel1
 	return ec._GitRepoStatusResults(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNHealthCheckParams2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐHealthCheckParams(ctx context.Context, sel ast.SelectionSet, v model.HealthCheckParams) graphql.Marshaler {
+func (ec *executionContext) marshalNHealthCheckParams2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐHealthCheckParams(ctx context.Context, sel ast.SelectionSet, v model.HealthCheckParams) graphql.Marshaler {
 	return ec._HealthCheckParams(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNHealthCheckParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐHealthCheckParams(ctx context.Context, sel ast.SelectionSet, v *model.HealthCheckParams) graphql.Marshaler {
+func (ec *executionContext) marshalNHealthCheckParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐHealthCheckParams(ctx context.Context, sel ast.SelectionSet, v *model.HealthCheckParams) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8144,11 +8144,11 @@ func (ec *executionContext) marshalNHealthCheckParams2ᚖgithubᚗcomᚋneel1996
 	return ec._HealthCheckParams(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNPullResult2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐPullResult(ctx context.Context, sel ast.SelectionSet, v model.PullResult) graphql.Marshaler {
+func (ec *executionContext) marshalNPullResult2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐPullResult(ctx context.Context, sel ast.SelectionSet, v model.PullResult) graphql.Marshaler {
 	return ec._PullResult(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNPullResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐPullResult(ctx context.Context, sel ast.SelectionSet, v *model.PullResult) graphql.Marshaler {
+func (ec *executionContext) marshalNPullResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐPullResult(ctx context.Context, sel ast.SelectionSet, v *model.PullResult) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8203,11 +8203,11 @@ func (ec *executionContext) marshalNString2ᚕᚖstring(ctx context.Context, sel
 	return ret
 }
 
-func (ec *executionContext) marshalNUnPushedCommitResult2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐUnPushedCommitResult(ctx context.Context, sel ast.SelectionSet, v model.UnPushedCommitResult) graphql.Marshaler {
+func (ec *executionContext) marshalNUnPushedCommitResult2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐUnPushedCommitResult(ctx context.Context, sel ast.SelectionSet, v model.UnPushedCommitResult) graphql.Marshaler {
 	return ec._UnPushedCommitResult(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNUnPushedCommitResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐUnPushedCommitResult(ctx context.Context, sel ast.SelectionSet, v *model.UnPushedCommitResult) graphql.Marshaler {
+func (ec *executionContext) marshalNUnPushedCommitResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐUnPushedCommitResult(ctx context.Context, sel ast.SelectionSet, v *model.UnPushedCommitResult) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8446,7 +8446,7 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a
 	return res
 }
 
-func (ec *executionContext) marshalNbranchCompareResults2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchCompareResults(ctx context.Context, sel ast.SelectionSet, v []*model.BranchCompareResults) graphql.Marshaler {
+func (ec *executionContext) marshalNbranchCompareResults2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchCompareResults(ctx context.Context, sel ast.SelectionSet, v []*model.BranchCompareResults) graphql.Marshaler {
 	ret := make(graphql.Array, len(v))
 	var wg sync.WaitGroup
 	isLen1 := len(v) == 1
@@ -8470,7 +8470,7 @@ func (ec *executionContext) marshalNbranchCompareResults2ᚕᚖgithubᚗcomᚋne
 			if !isLen1 {
 				defer wg.Done()
 			}
-			ret[i] = ec.marshalObranchCompareResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchCompareResults(ctx, sel, v[i])
+			ret[i] = ec.marshalObranchCompareResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchCompareResults(ctx, sel, v[i])
 		}
 		if isLen1 {
 			f(i)
@@ -8483,11 +8483,11 @@ func (ec *executionContext) marshalNbranchCompareResults2ᚕᚖgithubᚗcomᚋne
 	return ret
 }
 
-func (ec *executionContext) marshalNcodeFileType2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐCodeFileType(ctx context.Context, sel ast.SelectionSet, v model.CodeFileType) graphql.Marshaler {
+func (ec *executionContext) marshalNcodeFileType2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐCodeFileType(ctx context.Context, sel ast.SelectionSet, v model.CodeFileType) graphql.Marshaler {
 	return ec._codeFileType(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNcodeFileType2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐCodeFileType(ctx context.Context, sel ast.SelectionSet, v *model.CodeFileType) graphql.Marshaler {
+func (ec *executionContext) marshalNcodeFileType2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐCodeFileType(ctx context.Context, sel ast.SelectionSet, v *model.CodeFileType) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8497,11 +8497,11 @@ func (ec *executionContext) marshalNcodeFileType2ᚖgithubᚗcomᚋneel1996ᚋgi
 	return ec._codeFileType(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNdeleteStatus2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐDeleteStatus(ctx context.Context, sel ast.SelectionSet, v model.DeleteStatus) graphql.Marshaler {
+func (ec *executionContext) marshalNdeleteStatus2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐDeleteStatus(ctx context.Context, sel ast.SelectionSet, v model.DeleteStatus) graphql.Marshaler {
 	return ec._deleteStatus(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNdeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐDeleteStatus(ctx context.Context, sel ast.SelectionSet, v *model.DeleteStatus) graphql.Marshaler {
+func (ec *executionContext) marshalNdeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐDeleteStatus(ctx context.Context, sel ast.SelectionSet, v *model.DeleteStatus) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8511,11 +8511,11 @@ func (ec *executionContext) marshalNdeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgi
 	return ec._deleteStatus(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNfileLineChangeResult2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFileLineChangeResult(ctx context.Context, sel ast.SelectionSet, v model.FileLineChangeResult) graphql.Marshaler {
+func (ec *executionContext) marshalNfileLineChangeResult2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFileLineChangeResult(ctx context.Context, sel ast.SelectionSet, v model.FileLineChangeResult) graphql.Marshaler {
 	return ec._fileLineChangeResult(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNfileLineChangeResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFileLineChangeResult(ctx context.Context, sel ast.SelectionSet, v *model.FileLineChangeResult) graphql.Marshaler {
+func (ec *executionContext) marshalNfileLineChangeResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFileLineChangeResult(ctx context.Context, sel ast.SelectionSet, v *model.FileLineChangeResult) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8525,11 +8525,11 @@ func (ec *executionContext) marshalNfileLineChangeResult2ᚖgithubᚗcomᚋneel1
 	return ec._fileLineChangeResult(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNgitChangeResults2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitChangeResults(ctx context.Context, sel ast.SelectionSet, v model.GitChangeResults) graphql.Marshaler {
+func (ec *executionContext) marshalNgitChangeResults2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitChangeResults(ctx context.Context, sel ast.SelectionSet, v model.GitChangeResults) graphql.Marshaler {
 	return ec._gitChangeResults(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNgitChangeResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitChangeResults(ctx context.Context, sel ast.SelectionSet, v *model.GitChangeResults) graphql.Marshaler {
+func (ec *executionContext) marshalNgitChangeResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitChangeResults(ctx context.Context, sel ast.SelectionSet, v *model.GitChangeResults) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8539,7 +8539,7 @@ func (ec *executionContext) marshalNgitChangeResults2ᚖgithubᚗcomᚋneel1996
 	return ec._gitChangeResults(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitFileResult(ctx context.Context, sel ast.SelectionSet, v []*model.GitCommitFileResult) graphql.Marshaler {
+func (ec *executionContext) marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitFileResult(ctx context.Context, sel ast.SelectionSet, v []*model.GitCommitFileResult) graphql.Marshaler {
 	ret := make(graphql.Array, len(v))
 	var wg sync.WaitGroup
 	isLen1 := len(v) == 1
@@ -8563,7 +8563,7 @@ func (ec *executionContext) marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋnee
 			if !isLen1 {
 				defer wg.Done()
 			}
-			ret[i] = ec.marshalOgitCommitFileResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitFileResult(ctx, sel, v[i])
+			ret[i] = ec.marshalOgitCommitFileResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitFileResult(ctx, sel, v[i])
 		}
 		if isLen1 {
 			f(i)
@@ -8576,7 +8576,7 @@ func (ec *executionContext) marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋnee
 	return ret
 }
 
-func (ec *executionContext) marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx context.Context, sel ast.SelectionSet, v []*model.GitCommits) graphql.Marshaler {
+func (ec *executionContext) marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx context.Context, sel ast.SelectionSet, v []*model.GitCommits) graphql.Marshaler {
 	ret := make(graphql.Array, len(v))
 	var wg sync.WaitGroup
 	isLen1 := len(v) == 1
@@ -8600,7 +8600,7 @@ func (ec *executionContext) marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋg
 			if !isLen1 {
 				defer wg.Done()
 			}
-			ret[i] = ec.marshalOgitCommits2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx, sel, v[i])
+			ret[i] = ec.marshalOgitCommits2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx, sel, v[i])
 		}
 		if isLen1 {
 			f(i)
@@ -8613,7 +8613,7 @@ func (ec *executionContext) marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋg
 	return ret
 }
 
-func (ec *executionContext) marshalNremoteDetails2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteDetails(ctx context.Context, sel ast.SelectionSet, v []*model.RemoteDetails) graphql.Marshaler {
+func (ec *executionContext) marshalNremoteDetails2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteDetails(ctx context.Context, sel ast.SelectionSet, v []*model.RemoteDetails) graphql.Marshaler {
 	ret := make(graphql.Array, len(v))
 	var wg sync.WaitGroup
 	isLen1 := len(v) == 1
@@ -8637,7 +8637,7 @@ func (ec *executionContext) marshalNremoteDetails2ᚕᚖgithubᚗcomᚋneel1996
 			if !isLen1 {
 				defer wg.Done()
 			}
-			ret[i] = ec.marshalOremoteDetails2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteDetails(ctx, sel, v[i])
+			ret[i] = ec.marshalOremoteDetails2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteDetails(ctx, sel, v[i])
 		}
 		if isLen1 {
 			f(i)
@@ -8650,11 +8650,11 @@ func (ec *executionContext) marshalNremoteDetails2ᚕᚖgithubᚗcomᚋneel1996
 	return ret
 }
 
-func (ec *executionContext) marshalNremoteMutationResult2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteMutationResult(ctx context.Context, sel ast.SelectionSet, v model.RemoteMutationResult) graphql.Marshaler {
+func (ec *executionContext) marshalNremoteMutationResult2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteMutationResult(ctx context.Context, sel ast.SelectionSet, v model.RemoteMutationResult) graphql.Marshaler {
 	return ec._remoteMutationResult(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteMutationResult(ctx context.Context, sel ast.SelectionSet, v *model.RemoteMutationResult) graphql.Marshaler {
+func (ec *executionContext) marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteMutationResult(ctx context.Context, sel ast.SelectionSet, v *model.RemoteMutationResult) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8664,11 +8664,11 @@ func (ec *executionContext) marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1
 	return ec._remoteMutationResult(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNsettingsDataResults2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐSettingsDataResults(ctx context.Context, sel ast.SelectionSet, v model.SettingsDataResults) graphql.Marshaler {
+func (ec *executionContext) marshalNsettingsDataResults2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐSettingsDataResults(ctx context.Context, sel ast.SelectionSet, v model.SettingsDataResults) graphql.Marshaler {
 	return ec._settingsDataResults(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNsettingsDataResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐSettingsDataResults(ctx context.Context, sel ast.SelectionSet, v *model.SettingsDataResults) graphql.Marshaler {
+func (ec *executionContext) marshalNsettingsDataResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐSettingsDataResults(ctx context.Context, sel ast.SelectionSet, v *model.SettingsDataResults) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8966,21 +8966,21 @@ func (ec *executionContext) marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgen
 	return ec.___Type(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalObranchCompareResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchCompareResults(ctx context.Context, sel ast.SelectionSet, v *model.BranchCompareResults) graphql.Marshaler {
+func (ec *executionContext) marshalObranchCompareResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchCompareResults(ctx context.Context, sel ast.SelectionSet, v *model.BranchCompareResults) graphql.Marshaler {
 	if v == nil {
 		return graphql.Null
 	}
 	return ec._branchCompareResults(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalOgitCommitFileResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitFileResult(ctx context.Context, sel ast.SelectionSet, v *model.GitCommitFileResult) graphql.Marshaler {
+func (ec *executionContext) marshalOgitCommitFileResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitFileResult(ctx context.Context, sel ast.SelectionSet, v *model.GitCommitFileResult) graphql.Marshaler {
 	if v == nil {
 		return graphql.Null
 	}
 	return ec._gitCommitFileResult(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalOgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx context.Context, sel ast.SelectionSet, v []*model.GitCommits) graphql.Marshaler {
+func (ec *executionContext) marshalOgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx context.Context, sel ast.SelectionSet, v []*model.GitCommits) graphql.Marshaler {
 	if v == nil {
 		return graphql.Null
 	}
@@ -9007,7 +9007,7 @@ func (ec *executionContext) marshalOgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋg
 			if !isLen1 {
 				defer wg.Done()
 			}
-			ret[i] = ec.marshalOgitCommits2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx, sel, v[i])
+			ret[i] = ec.marshalOgitCommits2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx, sel, v[i])
 		}
 		if isLen1 {
 			f(i)
@@ -9020,14 +9020,14 @@ func (ec *executionContext) marshalOgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋg
 	return ret
 }
 
-func (ec *executionContext) marshalOgitCommits2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx context.Context, sel ast.SelectionSet, v *model.GitCommits) graphql.Marshaler {
+func (ec *executionContext) marshalOgitCommits2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx context.Context, sel ast.SelectionSet, v *model.GitCommits) graphql.Marshaler {
 	if v == nil {
 		return graphql.Null
 	}
 	return ec._gitCommits(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalOremoteDetails2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteDetails(ctx context.Context, sel ast.SelectionSet, v *model.RemoteDetails) graphql.Marshaler {
+func (ec *executionContext) marshalOremoteDetails2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteDetails(ctx context.Context, sel ast.SelectionSet, v *model.RemoteDetails) graphql.Marshaler {
 	if v == nil {
 		return graphql.Null
 	}
diff --git a/graph/schema.graphqls b/graph/schema.graphqls
index 98c072a..276aab7 100644
--- a/graph/schema.graphqls
+++ b/graph/schema.graphqls
@@ -436,7 +436,7 @@ type Mutation {
         "The UUID of the repo. It will be available in the JSON data file"
         repoId: String!,
         "The message for the commit"
-        commitMessage: String!
+        commitMessage: [String]!
     ): String!
 
     "Pushes the commits to the remote"
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index 054a9e2..5dea3f8 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -5,15 +5,17 @@ package graph
 
 import (
 	"context"
-	"github.com/neel1996/gitconvex/git/branch"
-	"github.com/neel1996/gitconvex/git/remote"
-	"github.com/neel1996/gitconvex/init"
+	"github.com/neel1996/gitconvex/utils"
 
 	"github.com/neel1996/gitconvex/api"
 	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/remote"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/generated"
 	"github.com/neel1996/gitconvex/graph/model"
+	initialize "github.com/neel1996/gitconvex/init"
 )
 
 func (r *mutationResolver) AddRepo(ctx context.Context, repoName string, repoPath string, cloneSwitch bool, repoURL *string, initSwitch bool, authOption string, sshKeyPath *string, userName *string, password *string) (*model.AddRepoParams, error) {
@@ -245,7 +247,7 @@ func (r *mutationResolver) StageAllItems(ctx context.Context, repoID string) (st
 	return stageAllObject.StageAllItems(), nil
 }
 
-func (r *mutationResolver) CommitChanges(ctx context.Context, repoID string, commitMessage string) (string, error) {
+func (r *mutationResolver) CommitChanges(ctx context.Context, repoID string, commitMessage []*string) (string, error) {
 	logger.Log("Initiating commit changes request", global.StatusInfo)
 
 	repoChan := make(chan git.RepoDetails)
@@ -254,14 +256,10 @@ func (r *mutationResolver) CommitChanges(ctx context.Context, repoID string, com
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
 
-	var commitObject git.CommitInterface
-	commitObject = git.CommitStruct{
-		Repo:          repo.GitRepo,
-		CommitMessage: commitMessage,
-		RepoPath:      repo.RepoPath,
-	}
+	commitChanges := commit.NewCommitChanges(repo.GitRepo, utils.GenerateNonPointerArrayFrom(commitMessage))
+	commitOperation := commit.Operation{Changes: commitChanges}
 
-	return commitObject.CommitChanges(), nil
+	return commitOperation.GitCommitChange()
 }
 
 func (r *mutationResolver) PushToRemote(ctx context.Context, repoID string, remoteHost string, branch string) (string, error) {
@@ -710,4 +708,10 @@ func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
 type mutationResolver struct{ *Resolver }
 type queryResolver struct{ *Resolver }
 
+// !!! WARNING !!!
+// The code below was going to be deleted when updating resolvers. It has been copied here so you have
+// one last chance to move it out of harms way if you want. There are two reasons this happens:
+//  - When renaming or deleting a resolver the old code will be put in here. You can safely delete
+//    it when you're done.
+//  - You have helper methods in this file. Move them out to keep these resolver files clean.
 var logger global.Logger
diff --git a/utils/array_generator.go.go b/utils/array_generator.go
similarity index 51%
rename from utils/array_generator.go.go
rename to utils/array_generator.go
index 5e4da57..0706ee0 100644
--- a/utils/array_generator.go.go
+++ b/utils/array_generator.go
@@ -9,3 +9,13 @@ func GeneratePointerArrayFrom(array []string) []*string {
 
 	return pointerArray
 }
+
+func GenerateNonPointerArrayFrom(array []*string) []string {
+	var pointerArray []string
+
+	for _, element := range array {
+		pointerArray = append(pointerArray, *element)
+	}
+
+	return pointerArray
+}

From 3a6620f222e4959d7c6f25519d5c67c58eab35ee Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 13 Jul 2021 23:41:56 +0530
Subject: [PATCH 045/148] add new test suite for commit changes api

---
 build_scripts/clone_test_repo.sh      |  11 ++-
 git/branch/git_branch_compare_test.go |   7 +-
 git/commit/git_commit_changes_test.go | 132 ++++++++++----------------
 tests/git_commit_changes_test.go      |  53 -----------
 4 files changed, 63 insertions(+), 140 deletions(-)
 delete mode 100644 tests/git_commit_changes_test.go

diff --git a/build_scripts/clone_test_repo.sh b/build_scripts/clone_test_repo.sh
index fc5d826..5c68820 100755
--- a/build_scripts/clone_test_repo.sh
+++ b/build_scripts/clone_test_repo.sh
@@ -1,4 +1,13 @@
 #!/bin/bash
 
 git clone https://github.com/neel1996/gitconvex-test.git $GITCONVEX_TEST_REPO
-git init $GITCONVEX_TEST_REPO/no_head
\ No newline at end of file
+
+cd $GITCONVEX_TEST_REPO && \
+git config user.name "test" && \
+git config user.email "test@test.com"
+
+git init $GITCONVEX_TEST_REPO/no_head
+
+mkdir no_head_for_commit && \
+touch ./no_head_for_commit/no_head.txt  && \
+git init $GITCONVEX_TEST_REPO/no_head_for_commit
\ No newline at end of file
diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
index 149c7ca..868de04 100644
--- a/git/branch/git_branch_compare_test.go
+++ b/git/branch/git_branch_compare_test.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/commit"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/stretchr/testify/suite"
 	"io/ioutil"
@@ -121,9 +122,5 @@ func (suite *BranchCompareTestSuite) stageAndCommitTestFile() {
 		FileItem: suite.testFile,
 	}.StageItem()
 
-	git.CommitStruct{
-		Repo:          suite.repo,
-		CommitMessage: "Branch compare test commit",
-		RepoPath:      suite.repo.Workdir(),
-	}.CommitChanges()
+	_ = commit.NewCommitChanges(suite.repo, []string{"Branch compare test commit"}).Add()
 }
diff --git a/git/commit/git_commit_changes_test.go b/git/commit/git_commit_changes_test.go
index ea1c17b..675eb46 100644
--- a/git/commit/git_commit_changes_test.go
+++ b/git/commit/git_commit_changes_test.go
@@ -3,105 +3,75 @@ package commit
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"runtime/debug"
-	"strings"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"path/filepath"
+	"testing"
+	"time"
 )
 
-type Changes interface {
-	CommitChanges() string
+type CommitChangesTestSuite struct {
+	suite.Suite
+	repo          *git2go.Repository
+	noHeadRepo    *git2go.Repository
+	commitChanges Changes
+	commitMessage []string
 }
 
-type changes struct {
-	Repo          *git2go.Repository
-	CommitMessage string
-	RepoPath      string
+func TestCommitChangesTestSuite(t *testing.T) {
+	suite.Run(t, new(CommitChangesTestSuite))
 }
 
-func checkCommitError(err error) bool {
+func (suite *CommitChangesTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	if err != nil {
-		logger.Log(err.Error(), global.StatusError)
-		panic(err)
-		return true
+		fmt.Println(err)
 	}
-	return false
+
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head_for_commit"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
+	suite.repo = r
+	suite.noHeadRepo = noHeadRepo
+
+	config, _ := suite.noHeadRepo.Config()
+	_ = config.SetString("user.name", "test")
+	_ = config.SetString("user.email", "test@test.com")
+
+	suite.commitMessage = []string{"Test commit message " + time.Now().String()}
+	suite.commitChanges = NewCommitChanges(suite.repo, suite.commitMessage)
 }
 
-// CommitChanges commits the staged changes to the repo
-// Rewrites the repo index tree with the staged files to commit the changes
-func (c CommitStruct) AddChanges() string {
-	var errStatus bool
-	var headCommit *git2go.Commit
-
-	commitMessage := c.CommitMessage
-	repo := c.Repo
-
-	defer func() string {
-		if r := recover(); r != nil {
-			logger.Log(string(debug.Stack()), global.StatusError)
-			return global.CommitChangeError
-		}
-		return ""
-	}()
-
-	var formattedMessage = commitMessage
-	signature, signatureErr := repo.DefaultSignature()
-
-	if signatureErr != nil {
-		logger.Log(fmt.Sprintf("Error occurred while fetching repo signature -> %s", signatureErr.Error()), global.StatusError)
-		logger.Log("Setup you user name and email using `git config user.name and git config user.email`", global.StatusWarning)
-		return global.CommitChangeError
-	}
+func (suite *CommitChangesTestSuite) TestAdd_WhenChangesAreCommitted_ShouldReturnNil() {
+	err := suite.commitChanges.Add()
 
-	if strings.Contains(commitMessage, "||") {
-		splitMessage := strings.Split(commitMessage, "||")
-		formattedMessage = strings.Join(splitMessage, "\n")
-	}
+	suite.Nil(err)
+}
 
-	head, headErr := repo.Head()
-	if headErr != nil {
-		logger.Log("Repo has no HEAD. Proceeding with a NIL HEAD", global.StatusWarning)
-		headCommit = nil
-	} else {
-		var headCommitErr error
-		headCommit, headCommitErr = repo.LookupCommit(head.Target())
-		errStatus = checkCommitError(headCommitErr)
-	}
+func (suite *CommitChangesTestSuite) TestAdd_WhenCommitMessageIsMultiLine_ShouldCommitToRepo() {
+	suite.commitChanges = NewCommitChanges(suite.repo, []string{"Multi line commit", "Test 1"})
 
-	repoIndex, indexErr := repo.Index()
-	errStatus = checkCommitError(indexErr)
+	err := suite.commitChanges.Add()
 
-	newTreeId, writeTreeErr := repoIndex.WriteTree()
-	errStatus = checkCommitError(writeTreeErr)
+	suite.Nil(err)
+}
 
-	newTree, newTreeErr := repo.LookupTree(newTreeId)
-	errStatus = checkCommitError(newTreeErr)
+func (suite *CommitChangesTestSuite) TestAdd_WhenRepoHasNoSignature_ShouldReturnError() {
+	suite.commitChanges = NewCommitChanges(suite.noHeadRepo, []string{})
 
-	var (
-		newCommitId    *git2go.Oid
-		newCommitIdErr error
-	)
-	if headErr != nil {
-		newCommitId, newCommitIdErr = repo.CreateCommit("HEAD", signature, signature, formattedMessage, newTree)
-	} else {
-		newCommitId, newCommitIdErr = repo.CreateCommit("HEAD", signature, signature, formattedMessage, newTree, headCommit)
-	}
-	errStatus = checkCommitError(newCommitIdErr)
+	config, _ := suite.noHeadRepo.Config()
+	_ = config.SetString("user.name", "")
+	_ = config.SetString("user.email", "")
 
-	_, newCommitErr := repo.LookupCommit(newCommitId)
-	errStatus = checkCommitError(newCommitErr)
+	err := suite.commitChanges.Add()
 
-	head, headErr = repo.Head()
-	errStatus = checkCommitError(headErr)
+	suite.NotNil(err)
+}
 
-	newRef, newRefErr := head.SetTarget(newCommitId, formattedMessage)
-	errStatus = checkCommitError(newRefErr)
+func (suite *CommitChangesTestSuite) TestAdd_WhenRepoHasNoHead_ShouldCommitToHead() {
+	suite.commitChanges = NewCommitChanges(suite.noHeadRepo, []string{"Initial commit"})
 
-	if errStatus {
-		return global.CommitChangeError
-	} else {
-		logger.Log(fmt.Sprintf("New commit %s created", newCommitId.String()), global.StatusInfo)
-		logger.Log(newRef.Name(), global.StatusInfo)
-		return global.CommitChangeSuccess
-	}
+	err := suite.commitChanges.Add()
+
+	suite.Nil(err)
 }
diff --git a/tests/git_commit_changes_test.go b/tests/git_commit_changes_test.go
deleted file mode 100644
index d272484..0000000
--- a/tests/git_commit_changes_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package tests
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"io/ioutil"
-	"os"
-	"testing"
-)
-
-func TestCommitChanges(t *testing.T) {
-	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	repoPath := r.Workdir()
-
-	sampleFile := "untracked.txt"
-	err := ioutil.WriteFile(repoPath+"/"+sampleFile, []byte{byte(63)}, 0755)
-
-	var stageAllObjects git2.StageAllInterface
-	stageAllObjects = git2.StageAllStruct{Repo: r}
-
-	fmt.Println(err)
-	fmt.Println(stageAllObjects.StageAllItems())
-
-	type args struct {
-		repo          *git2go.Repository
-		commitMessage string
-	}
-	tests := []struct {
-		name string
-		args args
-		want string
-	}{
-		{name: "Git commit changes test case", args: struct {
-			repo          *git2go.Repository
-			commitMessage string
-		}{repo: r, commitMessage: "Test commit"}, want: "COMMIT_DONE"},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.CommitInterface
-			testObj = git2.CommitStruct{
-				Repo:          tt.args.repo,
-				CommitMessage: tt.args.commitMessage,
-				RepoPath:      repoPath,
-			}
-
-			got := testObj.CommitChanges()
-			assert.Equal(t, tt.want, got)
-		})
-	}
-}

From 7c9166ea96a1f5c82dee0d6390b5201d49a1842a Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 13 Jul 2021 23:42:15 +0530
Subject: [PATCH 046/148] delete old test suites for commit related apis

---
 tests/git_commit_compare_test.go    | 48 ----------------------
 tests/git_commit_files_test.go      | 45 --------------------
 tests/git_commit_log_search_test.go | 50 ----------------------
 tests/git_commit_logs_test.go       | 43 -------------------
 tests/git_unpushed_commits_test.go  | 64 -----------------------------
 5 files changed, 250 deletions(-)
 delete mode 100644 tests/git_commit_compare_test.go
 delete mode 100644 tests/git_commit_files_test.go
 delete mode 100644 tests/git_commit_log_search_test.go
 delete mode 100644 tests/git_commit_logs_test.go
 delete mode 100644 tests/git_unpushed_commits_test.go

diff --git a/tests/git_commit_compare_test.go b/tests/git_commit_compare_test.go
deleted file mode 100644
index b65c35a..0000000
--- a/tests/git_commit_compare_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package tests
-
-import (
-	"github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"os"
-	"testing"
-)
-
-func TestCompareCommit(t *testing.T) {
-	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-
-	sampleCommits := git2.CommitLogStruct{
-		Repo:            r,
-		ReferenceCommit: "",
-	}.CommitLogs()
-
-	type args struct {
-		repo                *git.Repository
-		baseCommitString    string
-		compareCommitString string
-	}
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git commit compare test case", args: struct {
-			repo                *git.Repository
-			baseCommitString    string
-			compareCommitString string
-		}{repo: r, baseCommitString: *sampleCommits.Commits[0].Hash, compareCommitString: *sampleCommits.Commits[1].Hash}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.CompareCommitInterface
-			testObj = git2.CompareCommitStruct{
-				Repo:                tt.args.repo,
-				BaseCommitString:    tt.args.baseCommitString,
-				CompareCommitString: tt.args.compareCommitString,
-			}
-
-			got := testObj.CompareCommit()
-
-			assert.NotZero(t, len(got))
-		})
-	}
-}
diff --git a/tests/git_commit_files_test.go b/tests/git_commit_files_test.go
deleted file mode 100644
index f2dbf8e..0000000
--- a/tests/git_commit_files_test.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"os"
-	"testing"
-)
-
-func TestCommitFileList(t *testing.T) {
-	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-
-	sampleCommits := git2.CommitLogStruct{
-		Repo:            r,
-		ReferenceCommit: "",
-	}.CommitLogs()
-
-	type args struct {
-		repo       *git.Repository
-		commitHash string
-	}
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git commit file list test case", args: struct {
-			repo       *git.Repository
-			commitHash string
-		}{repo: r, commitHash: *sampleCommits.Commits[0].Hash}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObject git2.CommitFileListInterface
-			testObject = git2.CommitFileListStruct{
-				Repo:       tt.args.repo,
-				CommitHash: tt.args.commitHash,
-			}
-
-			got := testObject.CommitFileList()
-
-			assert.NotZero(t, len(got))
-		})
-	}
-}
diff --git a/tests/git_commit_log_search_test.go b/tests/git_commit_log_search_test.go
deleted file mode 100644
index 49d313a..0000000
--- a/tests/git_commit_log_search_test.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"os"
-	"testing"
-)
-
-func TestSearchCommitLogs(t *testing.T) {
-	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-
-	sampleCommits := git2.CommitLogStruct{
-		Repo:            r,
-		ReferenceCommit: "",
-	}.CommitLogs()
-	hash := *sampleCommits.Commits[0].Hash
-
-	type args struct {
-		repo       *git.Repository
-		searchType string
-		searchKey  string
-	}
-
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git commit log search test case", args: struct {
-			repo       *git.Repository
-			searchType string
-			searchKey  string
-		}{repo: r, searchType: "hash", searchKey: hash}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.SearchCommitInterface
-			testObj = git2.SearchCommitStruct{
-				Repo:       tt.args.repo,
-				SearchType: tt.args.searchType,
-				SearchKey:  tt.args.searchKey,
-			}
-
-			got := testObj.SearchCommitLogs()
-
-			assert.NotZero(t, len(got))
-		})
-	}
-}
diff --git a/tests/git_commit_logs_test.go b/tests/git_commit_logs_test.go
deleted file mode 100644
index d3ca1b2..0000000
--- a/tests/git_commit_logs_test.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	assert2 "github.com/stretchr/testify/assert"
-	"os"
-	"testing"
-)
-
-func TestCommitLogs(t *testing.T) {
-	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-
-	type args struct {
-		repo      *git.Repository
-		skipCount int
-	}
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git commit logs test case", args: struct {
-			repo      *git.Repository
-			skipCount int
-		}{repo: r, skipCount: 0}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			assert := assert2.New(t)
-
-			var testObj git2.CommitLogInterface
-			testObj = git2.CommitLogStruct{
-				Repo:            tt.args.repo,
-				ReferenceCommit: "",
-			}
-
-			cLogs := testObj.CommitLogs()
-			gotTotal := *cLogs.TotalCommits
-
-			assert.NotZero(int(gotTotal))
-		})
-	}
-}
diff --git a/tests/git_unpushed_commits_test.go b/tests/git_unpushed_commits_test.go
deleted file mode 100644
index 130bc7b..0000000
--- a/tests/git_unpushed_commits_test.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package tests
-
-import (
-	"github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"io/ioutil"
-	"os"
-	"testing"
-)
-
-func TestUnPushedCommits(t *testing.T) {
-	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	repoPath := r.Workdir()
-
-	untrackedResult := "untracked.txt"
-
-	_ = ioutil.WriteFile(repoPath+untrackedResult, []byte{byte(63)}, 0755)
-
-	var stageObject git2.StageItemInterface
-	var commitObject git2.CommitInterface
-
-	stageObject = git2.StageItemStruct{
-		Repo:     r,
-		FileItem: untrackedResult,
-	}
-
-	commitObject = git2.CommitStruct{
-		Repo:          r,
-		CommitMessage: "Test Commit",
-	}
-
-	stageObject.StageItem()
-	commitObject.CommitChanges()
-
-	type args struct {
-		repo      *git.Repository
-		remoteRef string
-	}
-	tests := []struct {
-		name string
-		args args
-		want []*string
-	}{
-		{name: "Git unpushed commit list test case", args: struct {
-			repo      *git.Repository
-			remoteRef string
-		}{repo: r, remoteRef: "origin/master"}, want: []*string{}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.UnPushedCommitInterface
-			testObj = git2.UnPushedCommitStruct{
-				Repo:      tt.args.repo,
-				RemoteRef: tt.args.remoteRef,
-			}
-
-			got := testObj.UnPushedCommits()
-
-			assert.NotNil(t, got)
-			assert.NotEmpty(t, *got.GitCommits[0].CommitMessage)
-		})
-	}
-}

From 383327aec5a2d67e6070fc7ed2f168e5647562e5 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 14 Jul 2021 23:22:09 +0530
Subject: [PATCH 047/148] add new api for getting total commit logs

---
 git/commit/commit.go                 |  5 +++
 git/commit/git_total_commits.go      | 63 +++++++++++++++++++++++++++
 git/commit/git_total_commits_test.go | 49 +++++++++++++++++++++
 git/git_total_commits.go             | 65 ----------------------------
 tests/git_total_commits_test.go      | 42 ------------------
 5 files changed, 117 insertions(+), 107 deletions(-)
 create mode 100644 git/commit/git_total_commits.go
 create mode 100644 git/commit/git_total_commits_test.go
 delete mode 100644 git/git_total_commits.go
 delete mode 100644 tests/git_total_commits_test.go

diff --git a/git/commit/commit.go b/git/commit/commit.go
index d09499d..28abbec 100644
--- a/git/commit/commit.go
+++ b/git/commit/commit.go
@@ -10,6 +10,7 @@ type Commit interface {
 
 type Operation struct {
 	Changes Changes
+	Total   Total
 }
 
 func (c Operation) GitCommitChange() (string, error) {
@@ -22,3 +23,7 @@ func (c Operation) GitCommitChange() (string, error) {
 
 	return global.CommitChangeSuccess, nil
 }
+
+func (c Operation) GitTotalCommits() int {
+	return c.Total.Get()
+}
diff --git a/git/commit/git_total_commits.go b/git/commit/git_total_commits.go
new file mode 100644
index 0000000..2d18f2d
--- /dev/null
+++ b/git/commit/git_total_commits.go
@@ -0,0 +1,63 @@
+package commit
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type Total interface {
+	Get() int
+}
+
+type totalCommits struct {
+	repo *git2go.Repository
+}
+
+// Get function returns the total number of commits from the repo and commit message of the most recent commit
+func (t totalCommits) Get() int {
+	var total = 0
+	repo := t.repo
+
+	logItr, itrErr := repo.Walk()
+	if itrErr != nil {
+		logger.Log(fmt.Sprintf("Repo has no logs -> %s", itrErr.Error()), global.StatusError)
+		return total
+	}
+
+	commits, err := t.iterateCommitLogs(logItr)
+	if err != nil {
+		logger.Log(fmt.Sprintf("Unable to obtain commits for the repo"), global.StatusError)
+		return total
+
+	}
+
+	total = len(commits)
+	if total == 0 {
+		logger.Log("Repo has no commit logs", global.StatusError)
+		return total
+	}
+
+	logger.Log(fmt.Sprintf("Total commits in the repo -> %v", total), global.StatusInfo)
+	return total
+}
+
+func (t totalCommits) iterateCommitLogs(logItr *git2go.RevWalk) ([]git2go.Commit, error) {
+	var commits []git2go.Commit
+	_ = logItr.PushHead()
+
+	err := logItr.Iterate(func(commit *git2go.Commit) bool {
+		if commit != nil {
+			commits = append(commits, *commit)
+			return true
+		} else {
+			return false
+		}
+	})
+
+	return commits, err
+}
+
+func NewTotalCommits(repo *git2go.Repository) Total {
+	return totalCommits{repo: repo}
+}
diff --git a/git/commit/git_total_commits_test.go b/git/commit/git_total_commits_test.go
new file mode 100644
index 0000000..5b962ce
--- /dev/null
+++ b/git/commit/git_total_commits_test.go
@@ -0,0 +1,49 @@
+package commit
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+type TotalCommitsTestSuite struct {
+	suite.Suite
+	total      Total
+	repo       *git2go.Repository
+	noHeadRepo *git2go.Repository
+}
+
+func TestTotalCommitsTestSuite(t *testing.T) {
+	suite.Run(t, new(TotalCommitsTestSuite))
+}
+
+func (suite *TotalCommitsTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
+	suite.repo = r
+	suite.noHeadRepo = noHeadRepo
+	suite.total = NewTotalCommits(suite.repo)
+}
+
+func (suite *TotalCommitsTestSuite) TestGet_WhenLogsAreAvailable_ShouldReturnTotal() {
+	got := suite.total.Get()
+
+	suite.NotZero(got)
+}
+
+func (suite *TotalCommitsTestSuite) TestGet_WhenRepoHasNoLogs_ShouldReturnZero() {
+	suite.total = NewTotalCommits(suite.noHeadRepo)
+
+	got := suite.total.Get()
+
+	suite.Zero(got)
+}
diff --git a/git/git_total_commits.go b/git/git_total_commits.go
deleted file mode 100644
index 583b031..0000000
--- a/git/git_total_commits.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-)
-
-type AllCommitInterface interface {
-	AllCommits(commitChan chan AllCommitData)
-}
-
-type AllCommitStruct struct {
-	Repo *git2go.Repository
-}
-
-type AllCommitData struct {
-	TotalCommits float64
-	LatestCommit string
-}
-
-// AllCommits function returns the total number of commits from the repo and commit message of the most recent commit
-func (t AllCommitStruct) AllCommits(commitChan chan AllCommitData) {
-	repo := t.Repo
-	logItr, itrErr := repo.Walk()
-	var commits []git2go.Commit
-
-	if itrErr != nil {
-		logger.Log(fmt.Sprintf("Repo has no logs -> %s", itrErr.Error()), global.StatusError)
-		commitChan <- AllCommitData{
-			TotalCommits: 0,
-			LatestCommit: "No Commits Available!",
-		}
-	} else {
-		_ = logItr.PushHead()
-
-		err := logItr.Iterate(func(commit *git2go.Commit) bool {
-			if commit != nil {
-				commits = append(commits, *commit)
-				return true
-			} else {
-				return false
-			}
-		})
-
-		if err != nil {
-			logger.Log(fmt.Sprintf("Unable to obtain commits for the repo"), global.StatusError)
-			commitChan <- AllCommitData{
-				TotalCommits: 0,
-				LatestCommit: "No Commits Available!",
-			}
-
-		} else {
-			logger.Log(fmt.Sprintf("Total commits in the repo -> %v", len(commits)), global.StatusInfo)
-
-			if len(commits) > 0 {
-				commitChan <- AllCommitData{
-					TotalCommits: float64(len(commits)),
-					LatestCommit: commits[0].Message(),
-				}
-			}
-		}
-	}
-	close(commitChan)
-}
diff --git a/tests/git_total_commits_test.go b/tests/git_total_commits_test.go
deleted file mode 100644
index df9af7a..0000000
--- a/tests/git_total_commits_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"os"
-	"testing"
-)
-
-func TestTotalCommitLogs(t *testing.T) {
-	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-
-	logChan := make(chan git2.AllCommitData)
-
-	type args struct {
-		repo       *git.Repository
-		commitChan chan git2.AllCommitData
-	}
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git logs test case", args: struct {
-			repo       *git.Repository
-			commitChan chan git2.AllCommitData
-		}{repo: r, commitChan: logChan}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			zeroValue := float64(0)
-
-			var testObj git2.AllCommitInterface
-			testObj = git2.AllCommitStruct{Repo: tt.args.repo}
-			go testObj.AllCommits(tt.args.commitChan)
-			commits := <-logChan
-			commitLength := commits.TotalCommits
-
-			assert.Greater(t, commitLength, zeroValue)
-		})
-	}
-}

From 3d7a57b5e7a4c90c921584e410ddafd120694885 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 15 Jul 2021 23:25:35 +0530
Subject: [PATCH 048/148] add new interface design for mocking git2go functions

---
 build_scripts/generate_all_mocks.sh  |  4 ++
 git/commit/git_total_commits.go      | 22 ++++++----
 git/commit/git_total_commits_test.go | 20 ++++++---
 git/interface/repository.go          | 19 +++++++++
 git/interface/walk.go                |  1 +
 go.mod                               |  1 +
 go.sum                               | 20 +++++++++
 mocks/mock_repository.go             | 50 ++++++++++++++++++++++
 mocks/mock_walk.go                   | 63 ++++++++++++++++++++++++++++
 9 files changed, 187 insertions(+), 13 deletions(-)
 create mode 100644 build_scripts/generate_all_mocks.sh
 create mode 100644 git/interface/repository.go
 create mode 100644 git/interface/walk.go
 create mode 100644 mocks/mock_repository.go
 create mode 100644 mocks/mock_walk.go

diff --git a/build_scripts/generate_all_mocks.sh b/build_scripts/generate_all_mocks.sh
new file mode 100644
index 0000000..bc1253c
--- /dev/null
+++ b/build_scripts/generate_all_mocks.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+mockgen -source=../git/interface/repository.go -destination=../mocks/mock_repository.go -package=mocks
+mockgen -source=../git/interface/walk.go -destination=../mocks/mock_walk.go -package=mocks
\ No newline at end of file
diff --git a/git/commit/git_total_commits.go b/git/commit/git_total_commits.go
index 2d18f2d..05daef7 100644
--- a/git/commit/git_total_commits.go
+++ b/git/commit/git_total_commits.go
@@ -3,6 +3,7 @@ package commit
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
+	libgit_interface "github.com/neel1996/gitconvex/git/interface"
 	"github.com/neel1996/gitconvex/global"
 )
 
@@ -11,7 +12,8 @@ type Total interface {
 }
 
 type totalCommits struct {
-	repo *git2go.Repository
+	repo    libgit_interface.Repository
+	revWalk libgit_interface.RevWalk
 }
 
 // Get function returns the total number of commits from the repo and commit message of the most recent commit
@@ -25,7 +27,7 @@ func (t totalCommits) Get() int {
 		return total
 	}
 
-	commits, err := t.iterateCommitLogs(logItr)
+	commits, err := t.allCommitLogs(logItr)
 	if err != nil {
 		logger.Log(fmt.Sprintf("Unable to obtain commits for the repo"), global.StatusError)
 		return total
@@ -42,22 +44,26 @@ func (t totalCommits) Get() int {
 	return total
 }
 
-func (t totalCommits) iterateCommitLogs(logItr *git2go.RevWalk) ([]git2go.Commit, error) {
+func (t totalCommits) allCommitLogs(logItr libgit_interface.RevWalk) ([]git2go.Commit, error) {
 	var commits []git2go.Commit
 	_ = logItr.PushHead()
 
-	err := logItr.Iterate(func(commit *git2go.Commit) bool {
+	err := logItr.Iterate(revIterator(commits))
+
+	return commits, err
+}
+
+func revIterator(commits []git2go.Commit) git2go.RevWalkIterator {
+	return func(commit *git2go.Commit) bool {
 		if commit != nil {
 			commits = append(commits, *commit)
 			return true
 		} else {
 			return false
 		}
-	})
-
-	return commits, err
+	}
 }
 
-func NewTotalCommits(repo *git2go.Repository) Total {
+func NewTotalCommits(repo libgit_interface.Repository) Total {
 	return totalCommits{repo: repo}
 }
diff --git a/git/commit/git_total_commits_test.go b/git/commit/git_total_commits_test.go
index 5b962ce..bb0af12 100644
--- a/git/commit/git_total_commits_test.go
+++ b/git/commit/git_total_commits_test.go
@@ -1,8 +1,11 @@
 package commit
 
 import (
+	"errors"
 	"fmt"
+	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
 	"path/filepath"
@@ -11,9 +14,12 @@ import (
 
 type TotalCommitsTestSuite struct {
 	suite.Suite
-	total      Total
-	repo       *git2go.Repository
-	noHeadRepo *git2go.Repository
+	mockController *gomock.Controller
+	total          Total
+	repo           *git2go.Repository
+	mockRepo       *mocks.MockRepository
+	mockWalker     *mocks.MockRevWalk
+	noHeadRepo     *git2go.Repository
 }
 
 func TestTotalCommitsTestSuite(t *testing.T) {
@@ -29,9 +35,12 @@ func (suite *TotalCommitsTestSuite) SetupTest() {
 	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
 	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
 
+	suite.mockController = gomock.NewController(suite.T())
 	suite.repo = r
 	suite.noHeadRepo = noHeadRepo
-	suite.total = NewTotalCommits(suite.repo)
+	suite.mockWalker = mocks.NewMockRevWalk(suite.mockController)
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.total = NewTotalCommits(suite.mockRepo)
 }
 
 func (suite *TotalCommitsTestSuite) TestGet_WhenLogsAreAvailable_ShouldReturnTotal() {
@@ -41,7 +50,8 @@ func (suite *TotalCommitsTestSuite) TestGet_WhenLogsAreAvailable_ShouldReturnTot
 }
 
 func (suite *TotalCommitsTestSuite) TestGet_WhenRepoHasNoLogs_ShouldReturnZero() {
-	suite.total = NewTotalCommits(suite.noHeadRepo)
+	suite.total = NewTotalCommits(suite.mockRepo)
+	suite.mockRepo.EXPECT().Walk().Return(nil, errors.New("WALKER_ERROR"))
 
 	got := suite.total.Get()
 
diff --git a/git/interface/repository.go b/git/interface/repository.go
new file mode 100644
index 0000000..9de5136
--- /dev/null
+++ b/git/interface/repository.go
@@ -0,0 +1,19 @@
+package libgit_interface
+
+import git "github.com/libgit2/git2go/v31"
+
+type Repository interface {
+	Walk() (*git.RevWalk, error)
+}
+
+type repository struct {
+	repo *git.Repository
+}
+
+func (r repository) Walk() (*git.RevWalk, error) {
+	return r.repo.Walk()
+}
+
+func NewRepository(repo *git.Repository) Repository {
+	return repository{repo: repo}
+}
diff --git a/git/interface/walk.go b/git/interface/walk.go
new file mode 100644
index 0000000..e94471c
--- /dev/null
+++ b/git/interface/walk.go
@@ -0,0 +1 @@
+package libgit_interface
diff --git a/go.mod b/go.mod
index e693def..1fb13ea 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@ go 1.16
 
 require (
 	github.com/99designs/gqlgen v0.13.0
+	github.com/golang/mock v1.6.0 // indirect
 	github.com/google/uuid v1.1.2
 	github.com/gorilla/mux v1.8.0
 	github.com/libgit2/git2go/v31 v31.4.10
diff --git a/go.sum b/go.sum
index 050cf22..bb54219 100644
--- a/go.sum
+++ b/go.sum
@@ -17,6 +17,8 @@ github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c h1:TUuUh0Xgj97tLMN
 github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
 github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
 github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
 github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
@@ -73,30 +75,48 @@ github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2
 github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
 github.com/vektah/gqlparser/v2 v2.1.0 h1:uiKJ+T5HMGGQM2kRKQ8Pxw8+Zq9qhhZhz/lieYvCMns=
 github.com/vektah/gqlparser/v2 v2.1.0/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k=
 golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201204225414-ed752295db88 h1:KmZPnMocC93w341XZp26yTJg8Za7lhb2KhkYmixoeso=
 golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589 h1:rjUrONFu4kLchcZTfp3/96bR8bW8dIa8uz3cR5n0cgM=
 golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
new file mode 100644
index 0000000..17a735e
--- /dev/null
+++ b/mocks/mock_repository.go
@@ -0,0 +1,50 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ../git/interface/repository.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	libgit_interface "github.com/neel1996/gitconvex/git/interface"
+)
+
+// MockRepository is a mock of Repository interface.
+type MockRepository struct {
+	ctrl     *gomock.Controller
+	recorder *MockRepositoryMockRecorder
+}
+
+// MockRepositoryMockRecorder is the mock recorder for MockRepository.
+type MockRepositoryMockRecorder struct {
+	mock *MockRepository
+}
+
+// NewMockRepository creates a new mock instance.
+func NewMockRepository(ctrl *gomock.Controller) *MockRepository {
+	mock := &MockRepository{ctrl: ctrl}
+	mock.recorder = &MockRepositoryMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
+	return m.recorder
+}
+
+// Walk mocks base method.
+func (m *MockRepository) Walk() (libgit_interface.RevWalk, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Walk")
+	ret0, _ := ret[0].(libgit_interface.RevWalk)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Walk indicates an expected call of Walk.
+func (mr *MockRepositoryMockRecorder) Walk() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Walk", reflect.TypeOf((*MockRepository)(nil).Walk))
+}
diff --git a/mocks/mock_walk.go b/mocks/mock_walk.go
new file mode 100644
index 0000000..c9b6a0a
--- /dev/null
+++ b/mocks/mock_walk.go
@@ -0,0 +1,63 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ../git/interface/walk.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockRevWalk is a mock of RevWalk interface.
+type MockRevWalk struct {
+	ctrl     *gomock.Controller
+	recorder *MockRevWalkMockRecorder
+}
+
+// MockRevWalkMockRecorder is the mock recorder for MockRevWalk.
+type MockRevWalkMockRecorder struct {
+	mock *MockRevWalk
+}
+
+// NewMockRevWalk creates a new mock instance.
+func NewMockRevWalk(ctrl *gomock.Controller) *MockRevWalk {
+	mock := &MockRevWalk{ctrl: ctrl}
+	mock.recorder = &MockRevWalkMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockRevWalk) EXPECT() *MockRevWalkMockRecorder {
+	return m.recorder
+}
+
+// Iterate mocks base method.
+func (m *MockRevWalk) Iterate(iterator git.RevWalkIterator) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Iterate", iterator)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Iterate indicates an expected call of Iterate.
+func (mr *MockRevWalkMockRecorder) Iterate(iterator interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterate", reflect.TypeOf((*MockRevWalk)(nil).Iterate), iterator)
+}
+
+// PushHead mocks base method.
+func (m *MockRevWalk) PushHead() error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "PushHead")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// PushHead indicates an expected call of PushHead.
+func (mr *MockRevWalkMockRecorder) PushHead() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PushHead", reflect.TypeOf((*MockRevWalk)(nil).PushHead))
+}

From be4d67417d4656e27182a1aa0eb743c29cdaff33 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 16 Jul 2021 23:03:26 +0530
Subject: [PATCH 049/148] rename interface package and update mocks

---
 build_scripts/generate_all_mocks.sh         |  4 ++--
 git/commit/git_total_commits.go             | 25 ++++++++++++---------
 git/commit/git_total_commits_test.go        | 10 +++++----
 git/interface/walk.go                       |  1 -
 git/{interface => middleware}/repository.go |  8 ++++---
 git/middleware/walk.go                      | 24 ++++++++++++++++++++
 mocks/mock_repository.go                    |  8 +++----
 mocks/mock_walk.go                          |  2 +-
 8 files changed, 56 insertions(+), 26 deletions(-)
 mode change 100644 => 100755 build_scripts/generate_all_mocks.sh
 delete mode 100644 git/interface/walk.go
 rename git/{interface => middleware}/repository.go (64%)
 create mode 100644 git/middleware/walk.go

diff --git a/build_scripts/generate_all_mocks.sh b/build_scripts/generate_all_mocks.sh
old mode 100644
new mode 100755
index bc1253c..8043a98
--- a/build_scripts/generate_all_mocks.sh
+++ b/build_scripts/generate_all_mocks.sh
@@ -1,4 +1,4 @@
 #!/bin/bash
 
-mockgen -source=../git/interface/repository.go -destination=../mocks/mock_repository.go -package=mocks
-mockgen -source=../git/interface/walk.go -destination=../mocks/mock_walk.go -package=mocks
\ No newline at end of file
+mockgen -source=../git/middleware/repository.go -destination=../mocks/mock_repository.go -package=mocks
+mockgen -source=../git/middleware/walk.go -destination=../mocks/mock_walk.go -package=mocks
\ No newline at end of file
diff --git a/git/commit/git_total_commits.go b/git/commit/git_total_commits.go
index 05daef7..0c00f2a 100644
--- a/git/commit/git_total_commits.go
+++ b/git/commit/git_total_commits.go
@@ -3,7 +3,7 @@ package commit
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
-	libgit_interface "github.com/neel1996/gitconvex/git/interface"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 )
 
@@ -12,8 +12,12 @@ type Total interface {
 }
 
 type totalCommits struct {
-	repo    libgit_interface.Repository
-	revWalk libgit_interface.RevWalk
+	repo    middleware.Repository
+	revWalk middleware.RevWalk
+}
+
+type commitType struct {
+	commits []git2go.Commit
 }
 
 // Get function returns the total number of commits from the repo and commit message of the most recent commit
@@ -31,7 +35,6 @@ func (t totalCommits) Get() int {
 	if err != nil {
 		logger.Log(fmt.Sprintf("Unable to obtain commits for the repo"), global.StatusError)
 		return total
-
 	}
 
 	total = len(commits)
@@ -44,19 +47,19 @@ func (t totalCommits) Get() int {
 	return total
 }
 
-func (t totalCommits) allCommitLogs(logItr libgit_interface.RevWalk) ([]git2go.Commit, error) {
-	var commits []git2go.Commit
+func (t totalCommits) allCommitLogs(logItr middleware.RevWalk) ([]git2go.Commit, error) {
+	var c commitType
 	_ = logItr.PushHead()
 
-	err := logItr.Iterate(revIterator(commits))
+	err := logItr.Iterate(revIterator(&c))
 
-	return commits, err
+	return c.commits, err
 }
 
-func revIterator(commits []git2go.Commit) git2go.RevWalkIterator {
+func revIterator(c *commitType) git2go.RevWalkIterator {
 	return func(commit *git2go.Commit) bool {
 		if commit != nil {
-			commits = append(commits, *commit)
+			c.commits = append(c.commits, *commit)
 			return true
 		} else {
 			return false
@@ -64,6 +67,6 @@ func revIterator(commits []git2go.Commit) git2go.RevWalkIterator {
 	}
 }
 
-func NewTotalCommits(repo libgit_interface.Repository) Total {
+func NewTotalCommits(repo middleware.Repository) Total {
 	return totalCommits{repo: repo}
 }
diff --git a/git/commit/git_total_commits_test.go b/git/commit/git_total_commits_test.go
index bb0af12..a0fc46b 100644
--- a/git/commit/git_total_commits_test.go
+++ b/git/commit/git_total_commits_test.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
@@ -16,7 +17,7 @@ type TotalCommitsTestSuite struct {
 	suite.Suite
 	mockController *gomock.Controller
 	total          Total
-	repo           *git2go.Repository
+	repo           middleware.Repository
 	mockRepo       *mocks.MockRepository
 	mockWalker     *mocks.MockRevWalk
 	noHeadRepo     *git2go.Repository
@@ -36,21 +37,22 @@ func (suite *TotalCommitsTestSuite) SetupTest() {
 	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
 
 	suite.mockController = gomock.NewController(suite.T())
-	suite.repo = r
+	suite.repo = middleware.NewRepository(r)
 	suite.noHeadRepo = noHeadRepo
-	suite.mockWalker = mocks.NewMockRevWalk(suite.mockController)
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockWalker = mocks.NewMockRevWalk(suite.mockController)
 	suite.total = NewTotalCommits(suite.mockRepo)
 }
 
 func (suite *TotalCommitsTestSuite) TestGet_WhenLogsAreAvailable_ShouldReturnTotal() {
+	suite.total = NewTotalCommits(suite.repo)
+
 	got := suite.total.Get()
 
 	suite.NotZero(got)
 }
 
 func (suite *TotalCommitsTestSuite) TestGet_WhenRepoHasNoLogs_ShouldReturnZero() {
-	suite.total = NewTotalCommits(suite.mockRepo)
 	suite.mockRepo.EXPECT().Walk().Return(nil, errors.New("WALKER_ERROR"))
 
 	got := suite.total.Get()
diff --git a/git/interface/walk.go b/git/interface/walk.go
deleted file mode 100644
index e94471c..0000000
--- a/git/interface/walk.go
+++ /dev/null
@@ -1 +0,0 @@
-package libgit_interface
diff --git a/git/interface/repository.go b/git/middleware/repository.go
similarity index 64%
rename from git/interface/repository.go
rename to git/middleware/repository.go
index 9de5136..8d1b747 100644
--- a/git/interface/repository.go
+++ b/git/middleware/repository.go
@@ -3,15 +3,17 @@ package libgit_interface
 import git "github.com/libgit2/git2go/v31"
 
 type Repository interface {
-	Walk() (*git.RevWalk, error)
+	Walk() (RevWalk, error)
 }
 
 type repository struct {
 	repo *git.Repository
 }
 
-func (r repository) Walk() (*git.RevWalk, error) {
-	return r.repo.Walk()
+func (r repository) Walk() (RevWalk, error) {
+	walk, err := r.repo.Walk()
+
+	return NewRevWalk(walk), err
 }
 
 func NewRepository(repo *git.Repository) Repository {
diff --git a/git/middleware/walk.go b/git/middleware/walk.go
new file mode 100644
index 0000000..fad2933
--- /dev/null
+++ b/git/middleware/walk.go
@@ -0,0 +1,24 @@
+package libgit_interface
+
+import git "github.com/libgit2/git2go/v31"
+
+type RevWalk interface {
+	Iterate(iterator git.RevWalkIterator) error
+	PushHead() error
+}
+
+type revWalk struct {
+	walk *git.RevWalk
+}
+
+func (w *revWalk) PushHead() error {
+	return w.walk.PushHead()
+}
+
+func (w *revWalk) Iterate(iterator git.RevWalkIterator) error {
+	return w.walk.Iterate(iterator)
+}
+
+func NewRevWalk(walk *git.RevWalk) RevWalk {
+	return &revWalk{walk: walk}
+}
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
index 17a735e..45de209 100644
--- a/mocks/mock_repository.go
+++ b/mocks/mock_repository.go
@@ -1,5 +1,5 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: ../git/interface/repository.go
+// Source: ../git/middleware/repository.go
 
 // Package mocks is a generated GoMock package.
 package mocks
@@ -8,7 +8,7 @@ import (
 	reflect "reflect"
 
 	gomock "github.com/golang/mock/gomock"
-	libgit_interface "github.com/neel1996/gitconvex/git/interface"
+	middleware "github.com/neel1996/gitconvex/git/middleware"
 )
 
 // MockRepository is a mock of Repository interface.
@@ -35,10 +35,10 @@ func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
 }
 
 // Walk mocks base method.
-func (m *MockRepository) Walk() (libgit_interface.RevWalk, error) {
+func (m *MockRepository) Walk() (middleware.RevWalk, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "Walk")
-	ret0, _ := ret[0].(libgit_interface.RevWalk)
+	ret0, _ := ret[0].(middleware.RevWalk)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
diff --git a/mocks/mock_walk.go b/mocks/mock_walk.go
index c9b6a0a..4425076 100644
--- a/mocks/mock_walk.go
+++ b/mocks/mock_walk.go
@@ -1,5 +1,5 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: ../git/interface/walk.go
+// Source: ../git/middleware/walk.go
 
 // Package mocks is a generated GoMock package.
 package mocks

From 1e392aa3efc3966e039c134a80ff89327f912683 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 16 Jul 2021 23:56:35 +0530
Subject: [PATCH 050/148] add new api for getting the latest commit message

---
 build_scripts/generate_all_mocks.sh          |  3 +-
 git/commit/git_latest_commit_message.go      | 53 ++++++++++++++
 git/commit/git_latest_commit_message_test.go | 76 ++++++++++++++++++++
 git/middleware/reference.go                  | 19 +++++
 git/middleware/repository.go                 | 16 ++++-
 git/middleware/walk.go                       |  2 +-
 mocks/mock_reference.go                      | 49 +++++++++++++
 mocks/mock_repository.go                     | 31 ++++++++
 8 files changed, 246 insertions(+), 3 deletions(-)
 create mode 100644 git/commit/git_latest_commit_message.go
 create mode 100644 git/commit/git_latest_commit_message_test.go
 create mode 100644 git/middleware/reference.go
 create mode 100644 mocks/mock_reference.go

diff --git a/build_scripts/generate_all_mocks.sh b/build_scripts/generate_all_mocks.sh
index 8043a98..811dac0 100755
--- a/build_scripts/generate_all_mocks.sh
+++ b/build_scripts/generate_all_mocks.sh
@@ -1,4 +1,5 @@
 #!/bin/bash
 
 mockgen -source=../git/middleware/repository.go -destination=../mocks/mock_repository.go -package=mocks
-mockgen -source=../git/middleware/walk.go -destination=../mocks/mock_walk.go -package=mocks
\ No newline at end of file
+mockgen -source=../git/middleware/walk.go -destination=../mocks/mock_walk.go -package=mocks
+mockgen -source=../git/middleware/reference.go -destination=../mocks/mock_reference.go -package=mocks
\ No newline at end of file
diff --git a/git/commit/git_latest_commit_message.go b/git/commit/git_latest_commit_message.go
new file mode 100644
index 0000000..d130d32
--- /dev/null
+++ b/git/commit/git_latest_commit_message.go
@@ -0,0 +1,53 @@
+package commit
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"strings"
+)
+
+type LatestMessage interface {
+	Get() string
+}
+
+type latestMessage struct {
+	repo middleware.Repository
+}
+
+func (l latestMessage) Get() string {
+	head, err := l.repo.Head()
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return ""
+	}
+
+	commit := head.Target()
+
+	lookupCommit, lookupError := l.repo.LookupCommit(commit)
+	if lookupError != nil {
+		logger.Log("Unable to lookup commit : "+lookupError.Error(), global.StatusError)
+		return ""
+	}
+
+	commitMessage := lookupCommit.Message()
+	if commitMessage != "" {
+		return l.truncateMultilineMessage(commitMessage)
+	}
+
+	return commitMessage
+}
+
+func (l latestMessage) truncateMultilineMessage(commitMessage string) string {
+	if strings.Contains(commitMessage, "\n") {
+		logger.Log("Truncating multiline commit message", global.StatusInfo)
+		commitMessage = strings.Split(commitMessage, "\n")[0]
+	}
+
+	logger.Log(fmt.Sprintf("HEAD commit message is : %v", commitMessage), global.StatusInfo)
+	return commitMessage
+}
+
+func NewLatestMessage(repo middleware.Repository) LatestMessage {
+	return latestMessage{repo: repo}
+}
diff --git a/git/commit/git_latest_commit_message_test.go b/git/commit/git_latest_commit_message_test.go
new file mode 100644
index 0000000..025791f
--- /dev/null
+++ b/git/commit/git_latest_commit_message_test.go
@@ -0,0 +1,76 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+type LatestMessageTestSuite struct {
+	suite.Suite
+	mockController *gomock.Controller
+	latestMessage  LatestMessage
+	repo           middleware.Repository
+	noHeadRepo     *git2go.Repository
+	mockRepo       *mocks.MockRepository
+	mockWalker     *mocks.MockRevWalk
+	mockReference  *mocks.MockReference
+}
+
+func TestLatestMessageTestSuite(t *testing.T) {
+	suite.Run(t, new(LatestMessageTestSuite))
+}
+
+func (suite *LatestMessageTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
+	suite.mockController = gomock.NewController(suite.T())
+	suite.repo = middleware.NewRepository(r)
+	suite.noHeadRepo = noHeadRepo
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockWalker = mocks.NewMockRevWalk(suite.mockController)
+	suite.mockReference = mocks.NewMockReference(suite.mockController)
+	suite.latestMessage = NewLatestMessage(suite.mockRepo)
+}
+
+func (suite *LatestMessageTestSuite) TestGet_WhenHeadIsValid_ShouldReturnCommitMessage() {
+	suite.latestMessage = NewLatestMessage(suite.repo)
+
+	got := suite.latestMessage.Get()
+
+	suite.NotEmpty(got)
+}
+
+func (suite *LatestMessageTestSuite) TestGet_WhenHeadIsInValid_ShouldReturnEmptyMessage() {
+	suite.repo = middleware.NewRepository(suite.noHeadRepo)
+	suite.latestMessage = NewLatestMessage(suite.repo)
+
+	got := suite.latestMessage.Get()
+
+	suite.Empty(got)
+}
+
+func (suite *LatestMessageTestSuite) TestGet_WhenCommitLookupFails_ShouldReturnEmptyMessage() {
+	oid, _ := git2go.NewOid("test")
+
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().Target().Return(oid)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	got := suite.latestMessage.Get()
+
+	suite.Empty(got)
+}
diff --git a/git/middleware/reference.go b/git/middleware/reference.go
new file mode 100644
index 0000000..5dbcc2f
--- /dev/null
+++ b/git/middleware/reference.go
@@ -0,0 +1,19 @@
+package middleware
+
+import git "github.com/libgit2/git2go/v31"
+
+type Reference interface {
+	Target() *git.Oid
+}
+
+type reference struct {
+	ref *git.Reference
+}
+
+func (r reference) Target() *git.Oid {
+	return r.ref.Target()
+}
+
+func NewReference(ref *git.Reference) Reference {
+	return reference{ref: ref}
+}
diff --git a/git/middleware/repository.go b/git/middleware/repository.go
index 8d1b747..e4c09d0 100644
--- a/git/middleware/repository.go
+++ b/git/middleware/repository.go
@@ -1,15 +1,29 @@
-package libgit_interface
+package middleware
 
 import git "github.com/libgit2/git2go/v31"
 
 type Repository interface {
 	Walk() (RevWalk, error)
+	Head() (Reference, error)
+	LookupCommit(oid *git.Oid) (*git.Commit, error)
 }
 
 type repository struct {
 	repo *git.Repository
 }
 
+func (r repository) Head() (Reference, error) {
+	head, err := r.repo.Head()
+	if err != nil {
+		return nil, err
+	}
+	return NewReference(head), nil
+}
+
+func (r repository) LookupCommit(oid *git.Oid) (*git.Commit, error) {
+	return r.repo.LookupCommit(oid)
+}
+
 func (r repository) Walk() (RevWalk, error) {
 	walk, err := r.repo.Walk()
 
diff --git a/git/middleware/walk.go b/git/middleware/walk.go
index fad2933..ea2fe37 100644
--- a/git/middleware/walk.go
+++ b/git/middleware/walk.go
@@ -1,4 +1,4 @@
-package libgit_interface
+package middleware
 
 import git "github.com/libgit2/git2go/v31"
 
diff --git a/mocks/mock_reference.go b/mocks/mock_reference.go
new file mode 100644
index 0000000..28e32c5
--- /dev/null
+++ b/mocks/mock_reference.go
@@ -0,0 +1,49 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ../git/middleware/reference.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockReference is a mock of Reference interface.
+type MockReference struct {
+	ctrl     *gomock.Controller
+	recorder *MockReferenceMockRecorder
+}
+
+// MockReferenceMockRecorder is the mock recorder for MockReference.
+type MockReferenceMockRecorder struct {
+	mock *MockReference
+}
+
+// NewMockReference creates a new mock instance.
+func NewMockReference(ctrl *gomock.Controller) *MockReference {
+	mock := &MockReference{ctrl: ctrl}
+	mock.recorder = &MockReferenceMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockReference) EXPECT() *MockReferenceMockRecorder {
+	return m.recorder
+}
+
+// Target mocks base method.
+func (m *MockReference) Target() *git.Oid {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Target")
+	ret0, _ := ret[0].(*git.Oid)
+	return ret0
+}
+
+// Target indicates an expected call of Target.
+func (mr *MockReferenceMockRecorder) Target() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Target", reflect.TypeOf((*MockReference)(nil).Target))
+}
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
index 45de209..f3d27e8 100644
--- a/mocks/mock_repository.go
+++ b/mocks/mock_repository.go
@@ -8,6 +8,7 @@ import (
 	reflect "reflect"
 
 	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
 	middleware "github.com/neel1996/gitconvex/git/middleware"
 )
 
@@ -34,6 +35,36 @@ func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
 	return m.recorder
 }
 
+// Head mocks base method.
+func (m *MockRepository) Head() (middleware.Reference, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Head")
+	ret0, _ := ret[0].(middleware.Reference)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Head indicates an expected call of Head.
+func (mr *MockRepositoryMockRecorder) Head() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Head", reflect.TypeOf((*MockRepository)(nil).Head))
+}
+
+// LookupCommit mocks base method.
+func (m *MockRepository) LookupCommit(oid *git.Oid) (*git.Commit, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "LookupCommit", oid)
+	ret0, _ := ret[0].(*git.Commit)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// LookupCommit indicates an expected call of LookupCommit.
+func (mr *MockRepositoryMockRecorder) LookupCommit(oid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupCommit", reflect.TypeOf((*MockRepository)(nil).LookupCommit), oid)
+}
+
 // Walk mocks base method.
 func (m *MockRepository) Walk() (middleware.RevWalk, error) {
 	m.ctrl.T.Helper()

From 16c6c60c432c5da48f509ee15da0795e90ce3fbb Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 17 Jul 2021 22:52:45 +0530
Subject: [PATCH 051/148] add new middleware and mocks to increase commit
 changes test coverage

---
 build_scripts/generate_all_mocks.sh   |   3 +-
 git/commit/git_commit_changes.go      |  13 +--
 git/commit/git_commit_changes_test.go | 124 ++++++++++++++++++++++----
 git/middleware/index.go               |  19 ++++
 git/middleware/reference.go           |   5 ++
 git/middleware/repository.go          |  25 ++++++
 mocks/mock_index.go                   |  50 +++++++++++
 mocks/mock_reference.go               |  15 ++++
 mocks/mock_repository.go              |  65 ++++++++++++++
 9 files changed, 296 insertions(+), 23 deletions(-)
 create mode 100644 git/middleware/index.go
 create mode 100644 mocks/mock_index.go

diff --git a/build_scripts/generate_all_mocks.sh b/build_scripts/generate_all_mocks.sh
index 811dac0..c88f602 100755
--- a/build_scripts/generate_all_mocks.sh
+++ b/build_scripts/generate_all_mocks.sh
@@ -2,4 +2,5 @@
 
 mockgen -source=../git/middleware/repository.go -destination=../mocks/mock_repository.go -package=mocks
 mockgen -source=../git/middleware/walk.go -destination=../mocks/mock_walk.go -package=mocks
-mockgen -source=../git/middleware/reference.go -destination=../mocks/mock_reference.go -package=mocks
\ No newline at end of file
+mockgen -source=../git/middleware/reference.go -destination=../mocks/mock_reference.go -package=mocks
+mockgen -source=../git/middleware/index.go -destination=../mocks/mock_index.go -package=mocks
\ No newline at end of file
diff --git a/git/commit/git_commit_changes.go b/git/commit/git_commit_changes.go
index 2adba8d..0bb2f13 100644
--- a/git/commit/git_commit_changes.go
+++ b/git/commit/git_commit_changes.go
@@ -3,6 +3,7 @@ package commit
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 	"strings"
 )
@@ -12,7 +13,7 @@ type Changes interface {
 }
 
 type changes struct {
-	repo          *git2go.Repository
+	repo          middleware.Repository
 	commitMessage []string
 }
 
@@ -60,7 +61,7 @@ func (c changes) Add() error {
 	return nil
 }
 
-func (c changes) validateSignature(repo *git2go.Repository) (*git2go.Signature, error) {
+func (c changes) validateSignature(repo middleware.Repository) (*git2go.Signature, error) {
 	signature, signatureErr := repo.DefaultSignature()
 	if signatureErr != nil {
 		logger.Log(fmt.Sprintf("Error occurred while fetching repo signature -> %s", signatureErr.Error()), global.StatusError)
@@ -71,7 +72,7 @@ func (c changes) validateSignature(repo *git2go.Repository) (*git2go.Signature,
 	return signature, nil
 }
 
-func (c changes) setHeadToNewCommit(repo *git2go.Repository, newCommitId *git2go.Oid, formattedMessage string) error {
+func (c changes) setHeadToNewCommit(repo middleware.Repository, newCommitId *git2go.Oid, formattedMessage string) error {
 	if _, newCommitErr := repo.LookupCommit(newCommitId); newCommitErr != nil {
 		logger.Log(newCommitErr.Error(), global.StatusError)
 		return newCommitErr
@@ -92,7 +93,7 @@ func (c changes) setHeadToNewCommit(repo *git2go.Repository, newCommitId *git2go
 	return nil
 }
 
-func (c changes) createNewCommit(headCommit *git2go.Commit, repo *git2go.Repository, signature *git2go.Signature, formattedMessage string, newTree *git2go.Tree) (*git2go.Oid, error) {
+func (c changes) createNewCommit(headCommit *git2go.Commit, repo middleware.Repository, signature *git2go.Signature, formattedMessage string, newTree *git2go.Tree) (*git2go.Oid, error) {
 	var (
 		newCommitId    *git2go.Oid
 		newCommitIdErr error
@@ -107,7 +108,7 @@ func (c changes) createNewCommit(headCommit *git2go.Commit, repo *git2go.Reposit
 	return newCommitId, newCommitIdErr
 }
 
-func (c changes) treeForNewCommit(repo *git2go.Repository) (*git2go.Tree, error) {
+func (c changes) treeForNewCommit(repo middleware.Repository) (*git2go.Tree, error) {
 	treeId, indexErr := c.updateRepoIndex()
 	if indexErr != nil {
 		logger.Log(indexErr.Error(), global.StatusError)
@@ -149,7 +150,7 @@ func (c changes) formatCommitMessage() string {
 	return strings.Join(c.commitMessage, "")
 }
 
-func NewCommitChanges(repo *git2go.Repository, message []string) Changes {
+func NewCommitChanges(repo middleware.Repository, message []string) Changes {
 	return changes{
 		repo:          repo,
 		commitMessage: message,
diff --git a/git/commit/git_commit_changes_test.go b/git/commit/git_commit_changes_test.go
index 675eb46..e7e321b 100644
--- a/git/commit/git_commit_changes_test.go
+++ b/git/commit/git_commit_changes_test.go
@@ -1,21 +1,30 @@
 package commit
 
 import (
+	"errors"
 	"fmt"
+	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
 	"path/filepath"
+	"strings"
 	"testing"
 	"time"
 )
 
 type CommitChangesTestSuite struct {
 	suite.Suite
-	repo          *git2go.Repository
-	noHeadRepo    *git2go.Repository
-	commitChanges Changes
-	commitMessage []string
+	mockController *gomock.Controller
+	repo           middleware.Repository
+	noHeadRepo     middleware.Repository
+	commitChanges  Changes
+	commitMessage  []string
+	mockRepo       *mocks.MockRepository
+	mockReference  *mocks.MockReference
+	mockIndex      *mocks.MockIndex
 }
 
 func TestCommitChangesTestSuite(t *testing.T) {
@@ -31,18 +40,21 @@ func (suite *CommitChangesTestSuite) SetupTest() {
 	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head_for_commit"
 	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
 
-	suite.repo = r
-	suite.noHeadRepo = noHeadRepo
+	suite.repo = middleware.NewRepository(r)
+	suite.noHeadRepo = middleware.NewRepository(noHeadRepo)
 
-	config, _ := suite.noHeadRepo.Config()
-	_ = config.SetString("user.name", "test")
-	_ = config.SetString("user.email", "test@test.com")
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockReference = mocks.NewMockReference(suite.mockController)
+	suite.mockIndex = mocks.NewMockIndex(suite.mockController)
 
 	suite.commitMessage = []string{"Test commit message " + time.Now().String()}
-	suite.commitChanges = NewCommitChanges(suite.repo, suite.commitMessage)
+	suite.commitChanges = NewCommitChanges(suite.mockRepo, suite.commitMessage)
 }
 
 func (suite *CommitChangesTestSuite) TestAdd_WhenChangesAreCommitted_ShouldReturnNil() {
+	suite.commitChanges = NewCommitChanges(suite.repo, suite.commitMessage)
+
 	err := suite.commitChanges.Add()
 
 	suite.Nil(err)
@@ -57,11 +69,7 @@ func (suite *CommitChangesTestSuite) TestAdd_WhenCommitMessageIsMultiLine_Should
 }
 
 func (suite *CommitChangesTestSuite) TestAdd_WhenRepoHasNoSignature_ShouldReturnError() {
-	suite.commitChanges = NewCommitChanges(suite.noHeadRepo, []string{})
-
-	config, _ := suite.noHeadRepo.Config()
-	_ = config.SetString("user.name", "")
-	_ = config.SetString("user.email", "")
+	suite.mockRepo.EXPECT().DefaultSignature().Return(nil, errors.New("SIGNATURE_ERROR"))
 
 	err := suite.commitChanges.Add()
 
@@ -69,9 +77,93 @@ func (suite *CommitChangesTestSuite) TestAdd_WhenRepoHasNoSignature_ShouldReturn
 }
 
 func (suite *CommitChangesTestSuite) TestAdd_WhenRepoHasNoHead_ShouldCommitToHead() {
-	suite.commitChanges = NewCommitChanges(suite.noHeadRepo, []string{"Initial commit"})
+	suite.commitMessage = []string{""}
+	suite.commitChanges = NewCommitChanges(suite.repo, suite.commitMessage)
 
 	err := suite.commitChanges.Add()
 
 	suite.Nil(err)
 }
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenRepoHeadIsInvalid_ShouldReturnError() {
+	oid, _ := git2go.NewOid("test")
+
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().Target().Return(oid)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenRepoIndexIsInvalid_ShouldReturnError() {
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("NO_HEAD"))
+	suite.mockRepo.EXPECT().Index().Return(nil, errors.New("INDEX_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenRepoTreeLookupFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("test")
+
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("NO_HEAD"))
+	suite.mockRepo.EXPECT().Index().Return(suite.mockIndex, nil)
+	suite.mockIndex.EXPECT().WriteTree().Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupTree(oid).Return(nil, errors.New("TREE_LOOKUP_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenCommitCreation_ShouldReturnError() {
+	oid, _ := git2go.NewOid("test")
+
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("NO_HEAD"))
+	suite.mockRepo.EXPECT().Index().Return(suite.mockIndex, nil)
+	suite.mockIndex.EXPECT().WriteTree().Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupTree(oid).Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CreateCommit(
+		"HEAD",
+		&git2go.Signature{},
+		&git2go.Signature{},
+		strings.Join(suite.commitMessage, ""),
+		&git2go.Tree{},
+	).Return(nil, errors.New("CREATE_COMMIT_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenSetNewHeadFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("test")
+	commitMessage := strings.Join(suite.commitMessage, "")
+
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("NO_HEAD"))
+	suite.mockRepo.EXPECT().Index().Return(suite.mockIndex, nil)
+	suite.mockIndex.EXPECT().WriteTree().Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupTree(oid).Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CreateCommit(
+		"HEAD",
+		&git2go.Signature{},
+		&git2go.Signature{},
+		commitMessage,
+		&git2go.Tree{},
+	).Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, nil)
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().SetTarget(oid, commitMessage).Return(nil, errors.New("SET_TARGET_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
diff --git a/git/middleware/index.go b/git/middleware/index.go
new file mode 100644
index 0000000..730cda0
--- /dev/null
+++ b/git/middleware/index.go
@@ -0,0 +1,19 @@
+package middleware
+
+import git "github.com/libgit2/git2go/v31"
+
+type Index interface {
+	WriteTree() (*git.Oid, error)
+}
+
+type index struct {
+	idx *git.Index
+}
+
+func (i index) WriteTree() (*git.Oid, error) {
+	return i.idx.WriteTree()
+}
+
+func NewIndex(idx *git.Index) Index {
+	return index{idx: idx}
+}
diff --git a/git/middleware/reference.go b/git/middleware/reference.go
index 5dbcc2f..3ba9fa7 100644
--- a/git/middleware/reference.go
+++ b/git/middleware/reference.go
@@ -4,6 +4,7 @@ import git "github.com/libgit2/git2go/v31"
 
 type Reference interface {
 	Target() *git.Oid
+	SetTarget(id *git.Oid, message string) (*git.Reference, error)
 }
 
 type reference struct {
@@ -14,6 +15,10 @@ func (r reference) Target() *git.Oid {
 	return r.ref.Target()
 }
 
+func (r reference) SetTarget(id *git.Oid, message string) (*git.Reference, error) {
+	return r.ref.SetTarget(id, message)
+}
+
 func NewReference(ref *git.Reference) Reference {
 	return reference{ref: ref}
 }
diff --git a/git/middleware/repository.go b/git/middleware/repository.go
index e4c09d0..cb82ef9 100644
--- a/git/middleware/repository.go
+++ b/git/middleware/repository.go
@@ -6,12 +6,21 @@ type Repository interface {
 	Walk() (RevWalk, error)
 	Head() (Reference, error)
 	LookupCommit(oid *git.Oid) (*git.Commit, error)
+	DefaultSignature() (*git.Signature, error)
+	LookupTree(id *git.Oid) (*git.Tree, error)
+	Index() (Index, error)
+	CreateCommit(s string, signature *git.Signature, signature2 *git.Signature, message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error)
 }
 
 type repository struct {
 	repo *git.Repository
 }
 
+func (r repository) CreateCommit(s string, signature *git.Signature, signature2 *git.Signature,
+	message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error) {
+	return r.repo.CreateCommit(s, signature, signature2, message, tree, parents...)
+}
+
 func (r repository) Head() (Reference, error) {
 	head, err := r.repo.Head()
 	if err != nil {
@@ -20,6 +29,14 @@ func (r repository) Head() (Reference, error) {
 	return NewReference(head), nil
 }
 
+func (r repository) Index() (Index, error) {
+	idx, err := r.repo.Index()
+	if err != nil {
+		return idx, err
+	}
+	return NewIndex(idx), nil
+}
+
 func (r repository) LookupCommit(oid *git.Oid) (*git.Commit, error) {
 	return r.repo.LookupCommit(oid)
 }
@@ -30,6 +47,14 @@ func (r repository) Walk() (RevWalk, error) {
 	return NewRevWalk(walk), err
 }
 
+func (r repository) DefaultSignature() (*git.Signature, error) {
+	return r.repo.DefaultSignature()
+}
+
+func (r repository) LookupTree(id *git.Oid) (*git.Tree, error) {
+	return r.repo.LookupTree(id)
+}
+
 func NewRepository(repo *git.Repository) Repository {
 	return repository{repo: repo}
 }
diff --git a/mocks/mock_index.go b/mocks/mock_index.go
new file mode 100644
index 0000000..4405b23
--- /dev/null
+++ b/mocks/mock_index.go
@@ -0,0 +1,50 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ../git/middleware/index.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockIndex is a mock of Index interface.
+type MockIndex struct {
+	ctrl     *gomock.Controller
+	recorder *MockIndexMockRecorder
+}
+
+// MockIndexMockRecorder is the mock recorder for MockIndex.
+type MockIndexMockRecorder struct {
+	mock *MockIndex
+}
+
+// NewMockIndex creates a new mock instance.
+func NewMockIndex(ctrl *gomock.Controller) *MockIndex {
+	mock := &MockIndex{ctrl: ctrl}
+	mock.recorder = &MockIndexMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockIndex) EXPECT() *MockIndexMockRecorder {
+	return m.recorder
+}
+
+// WriteTree mocks base method.
+func (m *MockIndex) WriteTree() (*git.Oid, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "WriteTree")
+	ret0, _ := ret[0].(*git.Oid)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// WriteTree indicates an expected call of WriteTree.
+func (mr *MockIndexMockRecorder) WriteTree() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteTree", reflect.TypeOf((*MockIndex)(nil).WriteTree))
+}
diff --git a/mocks/mock_reference.go b/mocks/mock_reference.go
index 28e32c5..730eb0c 100644
--- a/mocks/mock_reference.go
+++ b/mocks/mock_reference.go
@@ -34,6 +34,21 @@ func (m *MockReference) EXPECT() *MockReferenceMockRecorder {
 	return m.recorder
 }
 
+// SetTarget mocks base method.
+func (m *MockReference) SetTarget(id *git.Oid, message string) (*git.Reference, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SetTarget", id, message)
+	ret0, _ := ret[0].(*git.Reference)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// SetTarget indicates an expected call of SetTarget.
+func (mr *MockReferenceMockRecorder) SetTarget(id, message interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTarget", reflect.TypeOf((*MockReference)(nil).SetTarget), id, message)
+}
+
 // Target mocks base method.
 func (m *MockReference) Target() *git.Oid {
 	m.ctrl.T.Helper()
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
index f3d27e8..e0ac746 100644
--- a/mocks/mock_repository.go
+++ b/mocks/mock_repository.go
@@ -35,6 +35,41 @@ func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
 	return m.recorder
 }
 
+// CreateCommit mocks base method.
+func (m *MockRepository) CreateCommit(s string, signature, signature2 *git.Signature, message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{s, signature, signature2, message, tree}
+	for _, a := range parents {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "CreateCommit", varargs...)
+	ret0, _ := ret[0].(*git.Oid)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateCommit indicates an expected call of CreateCommit.
+func (mr *MockRepositoryMockRecorder) CreateCommit(s, signature, signature2, message, tree interface{}, parents ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{s, signature, signature2, message, tree}, parents...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateCommit", reflect.TypeOf((*MockRepository)(nil).CreateCommit), varargs...)
+}
+
+// DefaultSignature mocks base method.
+func (m *MockRepository) DefaultSignature() (*git.Signature, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DefaultSignature")
+	ret0, _ := ret[0].(*git.Signature)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// DefaultSignature indicates an expected call of DefaultSignature.
+func (mr *MockRepositoryMockRecorder) DefaultSignature() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultSignature", reflect.TypeOf((*MockRepository)(nil).DefaultSignature))
+}
+
 // Head mocks base method.
 func (m *MockRepository) Head() (middleware.Reference, error) {
 	m.ctrl.T.Helper()
@@ -50,6 +85,21 @@ func (mr *MockRepositoryMockRecorder) Head() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Head", reflect.TypeOf((*MockRepository)(nil).Head))
 }
 
+// Index mocks base method.
+func (m *MockRepository) Index() (middleware.Index, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Index")
+	ret0, _ := ret[0].(middleware.Index)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Index indicates an expected call of Index.
+func (mr *MockRepositoryMockRecorder) Index() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Index", reflect.TypeOf((*MockRepository)(nil).Index))
+}
+
 // LookupCommit mocks base method.
 func (m *MockRepository) LookupCommit(oid *git.Oid) (*git.Commit, error) {
 	m.ctrl.T.Helper()
@@ -65,6 +115,21 @@ func (mr *MockRepositoryMockRecorder) LookupCommit(oid interface{}) *gomock.Call
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupCommit", reflect.TypeOf((*MockRepository)(nil).LookupCommit), oid)
 }
 
+// LookupTree mocks base method.
+func (m *MockRepository) LookupTree(id *git.Oid) (*git.Tree, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "LookupTree", id)
+	ret0, _ := ret[0].(*git.Tree)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// LookupTree indicates an expected call of LookupTree.
+func (mr *MockRepositoryMockRecorder) LookupTree(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupTree", reflect.TypeOf((*MockRepository)(nil).LookupTree), id)
+}
+
 // Walk mocks base method.
 func (m *MockRepository) Walk() (middleware.RevWalk, error) {
 	m.ctrl.T.Helper()

From b2a709159572170f9b15d4421a98d94035890cfb Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 17 Jul 2021 23:04:27 +0530
Subject: [PATCH 052/148] improve coverage for latest commit message api

---
 git/commit/git_latest_commit_message_test.go | 25 ++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/git/commit/git_latest_commit_message_test.go b/git/commit/git_latest_commit_message_test.go
index 025791f..aa7a062 100644
--- a/git/commit/git_latest_commit_message_test.go
+++ b/git/commit/git_latest_commit_message_test.go
@@ -39,6 +39,9 @@ func (suite *LatestMessageTestSuite) SetupTest() {
 
 	suite.mockController = gomock.NewController(suite.T())
 	suite.repo = middleware.NewRepository(r)
+
+	_ = NewCommitChanges(suite.repo, []string{"New commit"}).Add()
+
 	suite.noHeadRepo = noHeadRepo
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
 	suite.mockWalker = mocks.NewMockRevWalk(suite.mockController)
@@ -47,11 +50,33 @@ func (suite *LatestMessageTestSuite) SetupTest() {
 }
 
 func (suite *LatestMessageTestSuite) TestGet_WhenHeadIsValid_ShouldReturnCommitMessage() {
+	_ = NewCommitChanges(suite.repo, []string{"New commit"}).Add()
+
 	suite.latestMessage = NewLatestMessage(suite.repo)
 
 	got := suite.latestMessage.Get()
 
 	suite.NotEmpty(got)
+	suite.Equal("New commit", got)
+}
+
+func (suite *LatestMessageTestSuite) TestGet_WhenCommitMessageIsMultiLine_ShouldReturnFirstLineOfTheMessage() {
+	_ = NewCommitChanges(suite.repo, []string{"New commit", "with two lines"}).Add()
+	suite.latestMessage = NewLatestMessage(suite.repo)
+
+	got := suite.latestMessage.Get()
+
+	suite.NotEmpty(got)
+	suite.Equal("New commit", got)
+}
+
+func (suite *LatestMessageTestSuite) TestGet_WhenCommitMessageIsEmpty_ShouldReturnEmptyMessage() {
+	_ = NewCommitChanges(suite.repo, []string{""}).Add()
+	suite.latestMessage = NewLatestMessage(suite.repo)
+
+	got := suite.latestMessage.Get()
+
+	suite.Empty(got)
 }
 
 func (suite *LatestMessageTestSuite) TestGet_WhenHeadIsInValid_ShouldReturnEmptyMessage() {

From 7b092bfb517f5994136d9f0b844e4d989b79d082 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 18 Jul 2021 00:02:04 +0530
Subject: [PATCH 053/148] update total commit test with new stub

---
 git/commit/git_total_commits.go           |  4 ++--
 git/commit/git_total_commits_test.go      | 19 +++++++++++++++-
 git/commit/git_total_commits_test_stub.go | 27 +++++++++++++++++++++++
 3 files changed, 47 insertions(+), 3 deletions(-)
 create mode 100644 git/commit/git_total_commits_test_stub.go

diff --git a/git/commit/git_total_commits.go b/git/commit/git_total_commits.go
index 0c00f2a..5a2f3f1 100644
--- a/git/commit/git_total_commits.go
+++ b/git/commit/git_total_commits.go
@@ -61,9 +61,9 @@ func revIterator(c *commitType) git2go.RevWalkIterator {
 		if commit != nil {
 			c.commits = append(c.commits, *commit)
 			return true
-		} else {
-			return false
 		}
+
+		return false
 	}
 }
 
diff --git a/git/commit/git_total_commits_test.go b/git/commit/git_total_commits_test.go
index a0fc46b..4c715ab 100644
--- a/git/commit/git_total_commits_test.go
+++ b/git/commit/git_total_commits_test.go
@@ -21,6 +21,7 @@ type TotalCommitsTestSuite struct {
 	mockRepo       *mocks.MockRepository
 	mockWalker     *mocks.MockRevWalk
 	noHeadRepo     *git2go.Repository
+	stub           middleware.RevWalk
 }
 
 func TestTotalCommitsTestSuite(t *testing.T) {
@@ -52,10 +53,26 @@ func (suite *TotalCommitsTestSuite) TestGet_WhenLogsAreAvailable_ShouldReturnTot
 	suite.NotZero(got)
 }
 
-func (suite *TotalCommitsTestSuite) TestGet_WhenRepoHasNoLogs_ShouldReturnZero() {
+func (suite *TotalCommitsTestSuite) TestGet_WhenRepoWalkFails_ShouldReturnZero() {
 	suite.mockRepo.EXPECT().Walk().Return(nil, errors.New("WALKER_ERROR"))
 
 	got := suite.total.Get()
 
 	suite.Zero(got)
 }
+
+func (suite *TotalCommitsTestSuite) TestGet_WhenRepoHasNoCommits_ShouldReturnZero() {
+	suite.mockRepo.EXPECT().Walk().Return(NewRevWalkStub(false), nil)
+
+	got := suite.total.Get()
+
+	suite.Zero(got)
+}
+
+func (suite *TotalCommitsTestSuite) TestGet_WhenIteratorReturnsError_ShouldReturnZero() {
+	suite.mockRepo.EXPECT().Walk().Return(NewRevWalkStub(true), nil)
+
+	got := suite.total.Get()
+
+	suite.Zero(got)
+}
diff --git a/git/commit/git_total_commits_test_stub.go b/git/commit/git_total_commits_test_stub.go
new file mode 100644
index 0000000..efe8052
--- /dev/null
+++ b/git/commit/git_total_commits_test_stub.go
@@ -0,0 +1,27 @@
+package commit
+
+import (
+	"errors"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+type revWalkStub struct {
+	walk                     *git2go.RevWalk
+	shouldIterateReturnError bool
+}
+
+func (w *revWalkStub) PushHead() error {
+	return nil
+}
+
+func (w *revWalkStub) Iterate(iterator git2go.RevWalkIterator) error {
+	if w.shouldIterateReturnError {
+		return errors.New("ITERATE_ERROR")
+	}
+	return nil
+}
+
+func NewRevWalkStub(shouldIterateReturnError bool) middleware.RevWalk {
+	return &revWalkStub{walk: &git2go.RevWalk{}, shouldIterateReturnError: shouldIterateReturnError}
+}

From 9d177e1fd1c1c5dc4e5d4f3de9a4ccb000a4df73 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 18 Jul 2021 00:09:32 +0530
Subject: [PATCH 054/148] add new test to commit change api

---
 git/commit/git_commit_changes_test.go | 47 +++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/git/commit/git_commit_changes_test.go b/git/commit/git_commit_changes_test.go
index e7e321b..9b1c15f 100644
--- a/git/commit/git_commit_changes_test.go
+++ b/git/commit/git_commit_changes_test.go
@@ -143,6 +143,53 @@ func (suite *CommitChangesTestSuite) TestAdd_WhenCommitCreation_ShouldReturnErro
 	suite.NotNil(err)
 }
 
+func (suite *CommitChangesTestSuite) TestAdd_WhenNewCommitLookupFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("test")
+	commitMessage := strings.Join(suite.commitMessage, "")
+
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("NO_HEAD"))
+	suite.mockRepo.EXPECT().Index().Return(suite.mockIndex, nil)
+	suite.mockIndex.EXPECT().WriteTree().Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupTree(oid).Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CreateCommit(
+		"HEAD",
+		&git2go.Signature{},
+		&git2go.Signature{},
+		commitMessage,
+		&git2go.Tree{},
+	).Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenNewHeadIsInvalid_ShouldReturnError() {
+	oid, _ := git2go.NewOid("test")
+	commitMessage := strings.Join(suite.commitMessage, "")
+
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("NO_HEAD"))
+	suite.mockRepo.EXPECT().Index().Return(suite.mockIndex, nil)
+	suite.mockIndex.EXPECT().WriteTree().Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupTree(oid).Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CreateCommit(
+		"HEAD",
+		&git2go.Signature{},
+		&git2go.Signature{},
+		commitMessage,
+		&git2go.Tree{},
+	).Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("HEAD_ERR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
 func (suite *CommitChangesTestSuite) TestAdd_WhenSetNewHeadFails_ShouldReturnError() {
 	oid, _ := git2go.NewOid("test")
 	commitMessage := strings.Join(suite.commitMessage, "")

From a3855e38c154c0d4de4e3fbebe6a272f6d6c4d39 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 18 Jul 2021 23:04:44 +0530
Subject: [PATCH 055/148] add new error constant to make errors more structured

---
 constants/common_strings.go    | 12 ++++++
 constants/current_version.go   |  7 ++++
 constants/default_dir_const.go |  5 +++
 constants/errors.go            | 32 ++++++++++++++++
 constants/global_logger.go     | 67 ++++++++++++++++++++++++++++++++++
 constants/status_strings.go    | 23 ++++++++++++
 6 files changed, 146 insertions(+)
 create mode 100644 constants/common_strings.go
 create mode 100644 constants/current_version.go
 create mode 100644 constants/default_dir_const.go
 create mode 100644 constants/errors.go
 create mode 100644 constants/global_logger.go
 create mode 100644 constants/status_strings.go

diff --git a/constants/common_strings.go b/constants/common_strings.go
new file mode 100644
index 0000000..7f4e6df
--- /dev/null
+++ b/constants/common_strings.go
@@ -0,0 +1,12 @@
+package constants
+
+const (
+	EnvFileName      = "gitconvex_env_config.json"
+	DatabaseFilePath = "/gitconvex-database/repo_datastore.json"
+	DefaultPort      = "9001"
+	PuttyGenExeName  = "puttygen.exe"
+	PageantExeName   = "pageant.exe"
+	SSHAuthOption    = "ssh"
+	HTTPSAuthOption  = "http"
+	NoAuthOption     = "noauth"
+)
diff --git a/constants/current_version.go b/constants/current_version.go
new file mode 100644
index 0000000..218a565
--- /dev/null
+++ b/constants/current_version.go
@@ -0,0 +1,7 @@
+package constants
+
+var CurrentVersion = "2.1.2"
+
+func GetCurrentVersion() string {
+	return CurrentVersion
+}
diff --git a/constants/default_dir_const.go b/constants/default_dir_const.go
new file mode 100644
index 0000000..7f2870d
--- /dev/null
+++ b/constants/default_dir_const.go
@@ -0,0 +1,5 @@
+package constants
+
+func GetDefaultDirectory() string {
+	return "GENERATED_ENV_STRING_GOES_HERE"
+}
diff --git a/constants/errors.go b/constants/errors.go
new file mode 100644
index 0000000..52a7c1c
--- /dev/null
+++ b/constants/errors.go
@@ -0,0 +1,32 @@
+package constants
+
+type ApiError struct {
+	error
+	ErrorCode   string
+	ErrorString string
+}
+
+var (
+	BranchAddError       = ApiError{ErrorCode: "BRANCH_ADD_FAILED", ErrorString: "Failed to add new branch"}
+	BranchCheckoutError  = ApiError{ErrorCode: "CHECKOUT_FAILED", ErrorString: "Failed to checkout branch"}
+	BranchDeleteError    = ApiError{ErrorCode: "BRANCH_DELETE_FAILED", ErrorString: "Failed to delete branch"}
+	RemoteAddError       = ApiError{ErrorCode: "REMOTE_ADD_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoteDeleteError    = ApiError{ErrorCode: "REMOTE_DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoteEditError      = ApiError{ErrorCode: "REMOTE_EDIT_FAILED", ErrorString: "Failed to delete add new remote"}
+	FetchFromRemoteError = ApiError{ErrorCode: "FETCH_ERROR", ErrorString: "Failed to delete add new remote"}
+	PullFromRemoteError  = ApiError{ErrorCode: "PULL_ERROR", ErrorString: "Failed to delete add new remote"}
+	StageItemError       = ApiError{ErrorCode: "ADD_ITEM_FAILED", ErrorString: "Failed to delete add new remote"}
+	StageAllItemsError   = ApiError{ErrorCode: "ALL_STAGE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoveItemError      = ApiError{ErrorCode: "STAGE_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoveAllItemsError  = ApiError{ErrorCode: "STAGE_ALL_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
+	CommitChangeError    = ApiError{ErrorCode: "COMMIT_FAILED", ErrorString: "Failed to delete add new remote"}
+	PushToRemoteError    = ApiError{ErrorCode: "PUSH_FAILED", ErrorString: "Failed to delete add new remote"}
+	PortUpdateError      = ApiError{ErrorCode: "PORT_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
+	DataFileUpdateError  = ApiError{ErrorCode: "DATAFILE_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RepoDeleteError      = ApiError{ErrorCode: "DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
+	CommitLogsError      = ApiError{ErrorCode: "LIST_COMMIT_LOGS_FAILED", ErrorString: "Failed to delete add new remote"}
+)
+
+func (e ApiError) Error() string {
+	return e.ErrorString
+}
diff --git a/constants/global_logger.go b/constants/global_logger.go
new file mode 100644
index 0000000..01278e5
--- /dev/null
+++ b/constants/global_logger.go
@@ -0,0 +1,67 @@
+package constants
+
+import (
+	"github.com/sirupsen/logrus"
+)
+
+// Global logger module for displaying the logs to the terminal
+
+type LoggerInterface interface {
+	info()
+	warn()
+	error()
+}
+
+type Logger struct {
+	Message string
+}
+
+const (
+	StatusError   = "StatusError"
+	StatusInfo    = "StatusInfo"
+	StatusWarning = "StatusWarning"
+)
+
+// Log gets the log message and the status selector
+// The log flag is chosen and color coded based on the status received
+func (l *Logger) Log(message string, status string) {
+	l.Message = message
+	switch status {
+	case StatusInfo:
+		l.info()
+		break
+	case StatusWarning:
+		l.warn()
+		break
+	case StatusError:
+		l.error()
+		break
+	default:
+		l.info()
+	}
+}
+
+func (l *Logger) info() {
+	logger := getLogger()
+	logger.Info(l.Message)
+}
+
+func (l *Logger) warn() {
+	logger := getLogger()
+	logger.Warn(l.Message)
+}
+
+func (l *Logger) error() {
+	logger := getLogger()
+	logger.Error(l.Message)
+}
+
+func getLogger() *logrus.Logger {
+	logger := logrus.New()
+	formatter := new(logrus.TextFormatter)
+	formatter.FullTimestamp = true
+	formatter.TimestampFormat = "2006-01-02 15:04:05"
+	formatter.PadLevelText = true
+	logger.SetFormatter(formatter)
+	return logger
+}
diff --git a/constants/status_strings.go b/constants/status_strings.go
new file mode 100644
index 0000000..c82e260
--- /dev/null
+++ b/constants/status_strings.go
@@ -0,0 +1,23 @@
+package constants
+
+const (
+	BranchAddSuccess       = "BRANCH_CREATION_SUCCESS"
+	BranchCheckoutSuccess  = "BRANCH_CHECKOUT_SUCCESS"
+	BranchDeleteSuccess    = "BRANCH_DELETE_SUCCESS"
+	RemoteAddSuccess       = "REMOTE_ADD_SUCCESS"
+	RemoteDeleteSuccess    = "REMOTE_DELETE_SUCCESS"
+	RemoteEditSuccess      = "REMOTE_EDIT_SUCCESS"
+	FetchNoNewChanges      = "NEW CHANGES ABSENT"
+	FetchFromRemoteSuccess = "CHANGES FETCHED FROM REMOTE"
+	PullNoNewChanges       = "NEW CHANGES ABSENT"
+	PullFromRemoteSuccess  = "PULL SUCCESS"
+	StageItemSuccess       = "ADD_ITEM_SUCCESS"
+	RemoveItemSuccess      = "STAGE_REMOVE_SUCCESS"
+	ResetAllSuccess        = "STAGE_ALL_REMOVE_SUCCESS"
+	StageAllSuccess        = "ALL_STAGED"
+	CommitChangeSuccess    = "COMMIT_DONE"
+	PushToRemoteSuccess    = "PUSH_SUCCESS"
+	PortUpdateSuccess      = "PORT_UPDATED"
+	DataFileUpdateSuccess  = "DATAFILE_UPDATE_SUCCESS"
+	RepoDeleteSuccess      = "DELETE_SUCCESS"
+)

From f0655fb9a33cc27d21c43af8a7f7be5544629327 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 20 Jul 2021 23:44:07 +0530
Subject: [PATCH 056/148] Revert "add new error constant to make errors more
 structured"

This reverts commit a3855e38
---
 constants/errors.go | 32 --------------------------------
 1 file changed, 32 deletions(-)
 delete mode 100644 constants/errors.go

diff --git a/constants/errors.go b/constants/errors.go
deleted file mode 100644
index 52a7c1c..0000000
--- a/constants/errors.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package constants
-
-type ApiError struct {
-	error
-	ErrorCode   string
-	ErrorString string
-}
-
-var (
-	BranchAddError       = ApiError{ErrorCode: "BRANCH_ADD_FAILED", ErrorString: "Failed to add new branch"}
-	BranchCheckoutError  = ApiError{ErrorCode: "CHECKOUT_FAILED", ErrorString: "Failed to checkout branch"}
-	BranchDeleteError    = ApiError{ErrorCode: "BRANCH_DELETE_FAILED", ErrorString: "Failed to delete branch"}
-	RemoteAddError       = ApiError{ErrorCode: "REMOTE_ADD_FAILED", ErrorString: "Failed to delete add new remote"}
-	RemoteDeleteError    = ApiError{ErrorCode: "REMOTE_DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
-	RemoteEditError      = ApiError{ErrorCode: "REMOTE_EDIT_FAILED", ErrorString: "Failed to delete add new remote"}
-	FetchFromRemoteError = ApiError{ErrorCode: "FETCH_ERROR", ErrorString: "Failed to delete add new remote"}
-	PullFromRemoteError  = ApiError{ErrorCode: "PULL_ERROR", ErrorString: "Failed to delete add new remote"}
-	StageItemError       = ApiError{ErrorCode: "ADD_ITEM_FAILED", ErrorString: "Failed to delete add new remote"}
-	StageAllItemsError   = ApiError{ErrorCode: "ALL_STAGE_FAILED", ErrorString: "Failed to delete add new remote"}
-	RemoveItemError      = ApiError{ErrorCode: "STAGE_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
-	RemoveAllItemsError  = ApiError{ErrorCode: "STAGE_ALL_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
-	CommitChangeError    = ApiError{ErrorCode: "COMMIT_FAILED", ErrorString: "Failed to delete add new remote"}
-	PushToRemoteError    = ApiError{ErrorCode: "PUSH_FAILED", ErrorString: "Failed to delete add new remote"}
-	PortUpdateError      = ApiError{ErrorCode: "PORT_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
-	DataFileUpdateError  = ApiError{ErrorCode: "DATAFILE_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
-	RepoDeleteError      = ApiError{ErrorCode: "DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
-	CommitLogsError      = ApiError{ErrorCode: "LIST_COMMIT_LOGS_FAILED", ErrorString: "Failed to delete add new remote"}
-)
-
-func (e ApiError) Error() string {
-	return e.ErrorString
-}

From d27b6eb598dfadf5862bc55b1007bf083ba89453 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 20 Jul 2021 23:45:56 +0530
Subject: [PATCH 057/148] restore global package and create new package for
 errors

---
 constants/common_strings.go     |  12 ---
 constants/current_version.go    |   7 --
 constants/default_dir_const.go  |   5 -
 constants/errors.go             |  32 ++++++
 constants/global_logger.go      |  67 -------------
 constants/status_strings.go     |  23 -----
 git/commit/git_total_commits.go |  31 +-----
 git/git_commit_logs.go          | 166 --------------------------------
 global/errors.go                |   2 -
 9 files changed, 35 insertions(+), 310 deletions(-)
 delete mode 100644 constants/common_strings.go
 delete mode 100644 constants/current_version.go
 delete mode 100644 constants/default_dir_const.go
 create mode 100644 constants/errors.go
 delete mode 100644 constants/global_logger.go
 delete mode 100644 constants/status_strings.go
 delete mode 100644 git/git_commit_logs.go

diff --git a/constants/common_strings.go b/constants/common_strings.go
deleted file mode 100644
index 7f4e6df..0000000
--- a/constants/common_strings.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package constants
-
-const (
-	EnvFileName      = "gitconvex_env_config.json"
-	DatabaseFilePath = "/gitconvex-database/repo_datastore.json"
-	DefaultPort      = "9001"
-	PuttyGenExeName  = "puttygen.exe"
-	PageantExeName   = "pageant.exe"
-	SSHAuthOption    = "ssh"
-	HTTPSAuthOption  = "http"
-	NoAuthOption     = "noauth"
-)
diff --git a/constants/current_version.go b/constants/current_version.go
deleted file mode 100644
index 218a565..0000000
--- a/constants/current_version.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package constants
-
-var CurrentVersion = "2.1.2"
-
-func GetCurrentVersion() string {
-	return CurrentVersion
-}
diff --git a/constants/default_dir_const.go b/constants/default_dir_const.go
deleted file mode 100644
index 7f2870d..0000000
--- a/constants/default_dir_const.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package constants
-
-func GetDefaultDirectory() string {
-	return "GENERATED_ENV_STRING_GOES_HERE"
-}
diff --git a/constants/errors.go b/constants/errors.go
new file mode 100644
index 0000000..52a7c1c
--- /dev/null
+++ b/constants/errors.go
@@ -0,0 +1,32 @@
+package constants
+
+type ApiError struct {
+	error
+	ErrorCode   string
+	ErrorString string
+}
+
+var (
+	BranchAddError       = ApiError{ErrorCode: "BRANCH_ADD_FAILED", ErrorString: "Failed to add new branch"}
+	BranchCheckoutError  = ApiError{ErrorCode: "CHECKOUT_FAILED", ErrorString: "Failed to checkout branch"}
+	BranchDeleteError    = ApiError{ErrorCode: "BRANCH_DELETE_FAILED", ErrorString: "Failed to delete branch"}
+	RemoteAddError       = ApiError{ErrorCode: "REMOTE_ADD_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoteDeleteError    = ApiError{ErrorCode: "REMOTE_DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoteEditError      = ApiError{ErrorCode: "REMOTE_EDIT_FAILED", ErrorString: "Failed to delete add new remote"}
+	FetchFromRemoteError = ApiError{ErrorCode: "FETCH_ERROR", ErrorString: "Failed to delete add new remote"}
+	PullFromRemoteError  = ApiError{ErrorCode: "PULL_ERROR", ErrorString: "Failed to delete add new remote"}
+	StageItemError       = ApiError{ErrorCode: "ADD_ITEM_FAILED", ErrorString: "Failed to delete add new remote"}
+	StageAllItemsError   = ApiError{ErrorCode: "ALL_STAGE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoveItemError      = ApiError{ErrorCode: "STAGE_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoveAllItemsError  = ApiError{ErrorCode: "STAGE_ALL_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
+	CommitChangeError    = ApiError{ErrorCode: "COMMIT_FAILED", ErrorString: "Failed to delete add new remote"}
+	PushToRemoteError    = ApiError{ErrorCode: "PUSH_FAILED", ErrorString: "Failed to delete add new remote"}
+	PortUpdateError      = ApiError{ErrorCode: "PORT_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
+	DataFileUpdateError  = ApiError{ErrorCode: "DATAFILE_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RepoDeleteError      = ApiError{ErrorCode: "DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
+	CommitLogsError      = ApiError{ErrorCode: "LIST_COMMIT_LOGS_FAILED", ErrorString: "Failed to delete add new remote"}
+)
+
+func (e ApiError) Error() string {
+	return e.ErrorString
+}
diff --git a/constants/global_logger.go b/constants/global_logger.go
deleted file mode 100644
index 01278e5..0000000
--- a/constants/global_logger.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package constants
-
-import (
-	"github.com/sirupsen/logrus"
-)
-
-// Global logger module for displaying the logs to the terminal
-
-type LoggerInterface interface {
-	info()
-	warn()
-	error()
-}
-
-type Logger struct {
-	Message string
-}
-
-const (
-	StatusError   = "StatusError"
-	StatusInfo    = "StatusInfo"
-	StatusWarning = "StatusWarning"
-)
-
-// Log gets the log message and the status selector
-// The log flag is chosen and color coded based on the status received
-func (l *Logger) Log(message string, status string) {
-	l.Message = message
-	switch status {
-	case StatusInfo:
-		l.info()
-		break
-	case StatusWarning:
-		l.warn()
-		break
-	case StatusError:
-		l.error()
-		break
-	default:
-		l.info()
-	}
-}
-
-func (l *Logger) info() {
-	logger := getLogger()
-	logger.Info(l.Message)
-}
-
-func (l *Logger) warn() {
-	logger := getLogger()
-	logger.Warn(l.Message)
-}
-
-func (l *Logger) error() {
-	logger := getLogger()
-	logger.Error(l.Message)
-}
-
-func getLogger() *logrus.Logger {
-	logger := logrus.New()
-	formatter := new(logrus.TextFormatter)
-	formatter.FullTimestamp = true
-	formatter.TimestampFormat = "2006-01-02 15:04:05"
-	formatter.PadLevelText = true
-	logger.SetFormatter(formatter)
-	return logger
-}
diff --git a/constants/status_strings.go b/constants/status_strings.go
deleted file mode 100644
index c82e260..0000000
--- a/constants/status_strings.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package constants
-
-const (
-	BranchAddSuccess       = "BRANCH_CREATION_SUCCESS"
-	BranchCheckoutSuccess  = "BRANCH_CHECKOUT_SUCCESS"
-	BranchDeleteSuccess    = "BRANCH_DELETE_SUCCESS"
-	RemoteAddSuccess       = "REMOTE_ADD_SUCCESS"
-	RemoteDeleteSuccess    = "REMOTE_DELETE_SUCCESS"
-	RemoteEditSuccess      = "REMOTE_EDIT_SUCCESS"
-	FetchNoNewChanges      = "NEW CHANGES ABSENT"
-	FetchFromRemoteSuccess = "CHANGES FETCHED FROM REMOTE"
-	PullNoNewChanges       = "NEW CHANGES ABSENT"
-	PullFromRemoteSuccess  = "PULL SUCCESS"
-	StageItemSuccess       = "ADD_ITEM_SUCCESS"
-	RemoveItemSuccess      = "STAGE_REMOVE_SUCCESS"
-	ResetAllSuccess        = "STAGE_ALL_REMOVE_SUCCESS"
-	StageAllSuccess        = "ALL_STAGED"
-	CommitChangeSuccess    = "COMMIT_DONE"
-	PushToRemoteSuccess    = "PUSH_SUCCESS"
-	PortUpdateSuccess      = "PORT_UPDATED"
-	DataFileUpdateSuccess  = "DATAFILE_UPDATE_SUCCESS"
-	RepoDeleteSuccess      = "DELETE_SUCCESS"
-)
diff --git a/git/commit/git_total_commits.go b/git/commit/git_total_commits.go
index 5a2f3f1..8162cec 100644
--- a/git/commit/git_total_commits.go
+++ b/git/commit/git_total_commits.go
@@ -25,15 +25,10 @@ func (t totalCommits) Get() int {
 	var total = 0
 	repo := t.repo
 
-	logItr, itrErr := repo.Walk()
-	if itrErr != nil {
-		logger.Log(fmt.Sprintf("Repo has no logs -> %s", itrErr.Error()), global.StatusError)
-		return total
-	}
-
-	commits, err := t.allCommitLogs(logItr)
+	allLogs := NewListAllLogs(repo)
+	commits, err := allLogs.Get()
 	if err != nil {
-		logger.Log(fmt.Sprintf("Unable to obtain commits for the repo"), global.StatusError)
+		logger.Log(fmt.Sprintf("Unable to obtain commits for the repo : %v", err.Error()), global.StatusError)
 		return total
 	}
 
@@ -47,26 +42,6 @@ func (t totalCommits) Get() int {
 	return total
 }
 
-func (t totalCommits) allCommitLogs(logItr middleware.RevWalk) ([]git2go.Commit, error) {
-	var c commitType
-	_ = logItr.PushHead()
-
-	err := logItr.Iterate(revIterator(&c))
-
-	return c.commits, err
-}
-
-func revIterator(c *commitType) git2go.RevWalkIterator {
-	return func(commit *git2go.Commit) bool {
-		if commit != nil {
-			c.commits = append(c.commits, *commit)
-			return true
-		}
-
-		return false
-	}
-}
-
 func NewTotalCommits(repo middleware.Repository) Total {
 	return totalCommits{repo: repo}
 }
diff --git a/git/git_commit_logs.go b/git/git_commit_logs.go
deleted file mode 100644
index 08db36a..0000000
--- a/git/git_commit_logs.go
+++ /dev/null
@@ -1,166 +0,0 @@
-package git
-
-import (
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-	"strings"
-)
-
-type CommitLogInterface interface {
-	CommitLogs() *model.GitCommitLogResults
-}
-
-type CommitLogStruct struct {
-	Repo            *git2go.Repository
-	ReferenceCommit string
-}
-
-// commitOrganizer collects and organizes the commit related information in the GitCommits struct
-func commitOrganizer(repo *git2go.Repository, commits []git2go.Commit) []*model.GitCommits {
-	var commitList []*model.GitCommits
-	for _, commit := range commits {
-		if commit.Id().String() != "" {
-			commitHash := commit.Id().String()
-			commitAuthor := strings.Split(commit.Author().Name, " ")[0]
-			commitMessage := strings.Split(commit.Message(), "\n")[0]
-			commitDate := commit.Committer().When.String()
-
-			parentCommit := commit.Parent(0)
-			if parentCommit == nil {
-				logger.Log("NIL parent Commit encountered", global.StatusWarning)
-				commitList = append(commitList, &model.GitCommits{
-					Hash:          &commitHash,
-					Author:        &commitAuthor,
-					CommitTime:    &commitDate,
-					CommitMessage: &commitMessage,
-				})
-				continue
-			}
-			parentTree, _ := parentCommit.Tree()
-			currentTree, _ := commit.Tree()
-
-			commitFileCount := 0
-			if parentTree != nil && currentTree != nil {
-				diff, diffErr := repo.DiffTreeToTree(parentTree, currentTree, nil)
-
-				if diffErr == nil {
-					commitFileCount, _ = diff.NumDeltas()
-				} else {
-					logger.Log(diffErr.Error(), global.StatusError)
-				}
-			} else {
-				logger.Log("Unable to fetch commit tree", global.StatusError)
-			}
-
-			commitList = append(commitList, &model.GitCommits{
-				Hash:             &commitHash,
-				Author:           &commitAuthor,
-				CommitTime:       &commitDate,
-				CommitMessage:    &commitMessage,
-				CommitFilesCount: &commitFileCount,
-			})
-		}
-	}
-	return commitList
-}
-
-// CommitLogs fetches the structured commit logs list for the target repo
-// Limits the length of commits to 10 for a single function call
-// The referenceCommit is used as a reference to fetch the commits in a linear manner
-func (c CommitLogStruct) CommitLogs() *model.GitCommitLogResults {
-	var commitLogs []git2go.Commit
-
-	repo := c.Repo
-	referenceCommit := c.ReferenceCommit
-
-	allCommitChan := make(chan AllCommitData)
-
-	var allCommitsObject AllCommitInterface
-	allCommitsObject = AllCommitStruct{Repo: repo}
-	go allCommitsObject.AllCommits(allCommitChan)
-
-	acc := <-allCommitChan
-	totalCommits := acc.TotalCommits
-
-	var counter int
-	counter = 0
-
-	logItr, itrErr := repo.Walk()
-	if itrErr != nil {
-		logger.Log(itrErr.Error(), global.StatusError)
-		return &model.GitCommitLogResults{
-			TotalCommits: &totalCommits,
-			Commits:      nil,
-		}
-	}
-
-	if referenceCommit == "" {
-		head, _ := repo.Head()
-		if head != nil {
-			if pushErr := logItr.PushHead(); pushErr != nil {
-				logger.Log(pushErr.Error(), global.StatusError)
-				return &model.GitCommitLogResults{
-					TotalCommits: &totalCommits,
-					Commits:      nil,
-				}
-			}
-
-			_ = logItr.Iterate(func(commit *git2go.Commit) bool {
-				if counter <= 10 {
-					commitLogs = append(commitLogs, *commit)
-					counter++
-					return true
-				}
-				return false
-			})
-		} else {
-			logger.Log("Unable to fetch repo HEAD", global.StatusError)
-			return &model.GitCommitLogResults{
-				TotalCommits: &totalCommits,
-				Commits:      nil,
-			}
-		}
-	} else {
-		refId, _ := git2go.NewOid(referenceCommit)
-		refCommit, refCommitErr := repo.LookupCommit(refId)
-
-		if refCommitErr == nil {
-			if pushErr := logItr.Push(refCommit.Id()); pushErr != nil {
-				logger.Log(pushErr.Error(), global.StatusError)
-				return &model.GitCommitLogResults{
-					TotalCommits: &totalCommits,
-					Commits:      nil,
-				}
-			}
-
-			_ = logItr.Iterate(func(commit *git2go.Commit) bool {
-				if counter <= 10 {
-					commitLogs = append(commitLogs, *commit)
-					counter++
-					return true
-				}
-				return false
-			})
-		} else {
-			logger.Log(refCommitErr.Error(), global.StatusError)
-			return &model.GitCommitLogResults{
-				TotalCommits: &totalCommits,
-				Commits:      nil,
-			}
-		}
-	}
-
-	if len(commitLogs) == 0 {
-		return &model.GitCommitLogResults{
-			TotalCommits: &totalCommits,
-			Commits:      nil,
-		}
-	}
-
-	refinedCommits := commitOrganizer(repo, commitLogs)
-	return &model.GitCommitLogResults{
-		TotalCommits: &totalCommits,
-		Commits:      refinedCommits,
-	}
-}
diff --git a/global/errors.go b/global/errors.go
index 41cd8db..e19980a 100644
--- a/global/errors.go
+++ b/global/errors.go
@@ -5,8 +5,6 @@ const (
 	BranchCheckoutError  = "CHECKOUT_FAILED"
 	BranchDeleteError    = "BRANCH_DELETE_FAILED"
 	RemoteAddError       = "REMOTE_ADD_FAILED"
-	RemoteDeleteError    = "REMOTE_DELETE_FAILED"
-	RemoteEditError      = "REMOTE_EDIT_FAILED"
 	FetchFromRemoteError = "FETCH_ERROR"
 	PullFromRemoteError  = "PULL_ERROR"
 	StageItemError       = "ADD_ITEM_FAILED"

From 442cc7f1f8de39eb97593c810f9a29b100fe0d70 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 20 Jul 2021 23:48:45 +0530
Subject: [PATCH 058/148] add api for getting the list of all commit logs

---
 git/commit/git_list_all_commit_logs.go        | 60 +++++++++++++++
 git/commit/git_list_all_commit_logs_test.go   | 74 +++++++++++++++++++
 .../git_list_all_commit_logs_test_stub.go}    |  6 +-
 3 files changed, 139 insertions(+), 1 deletion(-)
 create mode 100644 git/commit/git_list_all_commit_logs.go
 create mode 100644 git/commit/git_list_all_commit_logs_test.go
 rename git/commit/{git_total_commits_test_stub.go => stub/git_list_all_commit_logs_test_stub.go} (88%)

diff --git a/git/commit/git_list_all_commit_logs.go b/git/commit/git_list_all_commit_logs.go
new file mode 100644
index 0000000..21d187b
--- /dev/null
+++ b/git/commit/git_list_all_commit_logs.go
@@ -0,0 +1,60 @@
+package commit
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type ListAllLogs interface {
+	Get() ([]git2go.Commit, error)
+}
+
+type listAllLogs struct {
+	repo middleware.Repository
+}
+
+func (l listAllLogs) Get() ([]git2go.Commit, error) {
+	repo := l.repo
+
+	logItr, itrErr := repo.Walk()
+	if itrErr != nil {
+		logger.Log(fmt.Sprintf("Repo has no logs -> %s", itrErr.Error()), global.StatusError)
+		return nil, itrErr
+	}
+
+	commits, err := l.allCommitLogs(logItr)
+	if err != nil {
+		logger.Log(fmt.Sprintf("Unable to obtain commits for the repo"), global.StatusError)
+		return nil, err
+	}
+
+	return commits, nil
+}
+
+func (l listAllLogs) allCommitLogs(logItr middleware.RevWalk) ([]git2go.Commit, error) {
+	var c commitType
+	_ = logItr.PushHead()
+
+	err := logItr.Iterate(revIterator(&c))
+
+	return c.commits, err
+}
+
+func revIterator(c *commitType) git2go.RevWalkIterator {
+	return func(commit *git2go.Commit) bool {
+		if commit != nil {
+			c.commits = append(c.commits, *commit)
+			return true
+		}
+
+		return false
+	}
+}
+
+func NewListAllLogs(repo middleware.Repository) ListAllLogs {
+	return listAllLogs{
+		repo: repo,
+	}
+}
diff --git a/git/commit/git_list_all_commit_logs_test.go b/git/commit/git_list_all_commit_logs_test.go
new file mode 100644
index 0000000..1b8af19
--- /dev/null
+++ b/git/commit/git_list_all_commit_logs_test.go
@@ -0,0 +1,74 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/commit/stub"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type ListAllCommitLogsTestSuite struct {
+	suite.Suite
+	mockController    *gomock.Controller
+	mockRepo          *mocks.MockRepository
+	mockRevWalk       *mocks.MockRevWalk
+	repo              middleware.Repository
+	listAllCommitLogs ListAllLogs
+}
+
+func TestListAllCommitLogsTestSuite(t *testing.T) {
+	suite.Run(t, new(ListAllCommitLogsTestSuite))
+}
+
+func (suite *ListAllCommitLogsTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRevWalk = mocks.NewMockRevWalk(suite.mockController)
+
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.listAllCommitLogs = NewListAllLogs(suite.mockRepo)
+}
+
+func (suite *ListAllCommitLogsTestSuite) TestGet_WhenLogsAreAvailable_ShouldReturnCommitLogs() {
+	suite.listAllCommitLogs = NewListAllLogs(suite.repo)
+	got, err := suite.listAllCommitLogs.Get()
+
+	suite.NotZero(len(got))
+	suite.Nil(err)
+}
+
+func (suite *ListAllCommitLogsTestSuite) TestGet_WhenRepoWalkFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().Walk().Return(nil, errors.New("WALKER_ERROR"))
+
+	_, err := suite.listAllCommitLogs.Get()
+
+	suite.NotNil(err)
+}
+
+func (suite *ListAllCommitLogsTestSuite) TestGet_WhenRepoHasNoCommits_ShouldReturnNoCommitLogs() {
+	suite.mockRepo.EXPECT().Walk().Return(stub.NewRevWalkStub(false), nil)
+
+	got, err := suite.listAllCommitLogs.Get()
+
+	suite.Zero(len(got))
+	suite.Nil(err)
+}
+
+func (suite *ListAllCommitLogsTestSuite) TestGet_WhenIteratorReturnsError_ShouldReturnError() {
+	suite.mockRepo.EXPECT().Walk().Return(stub.NewRevWalkStub(true), nil)
+
+	_, err := suite.listAllCommitLogs.Get()
+
+	suite.NotNil(err)
+}
diff --git a/git/commit/git_total_commits_test_stub.go b/git/commit/stub/git_list_all_commit_logs_test_stub.go
similarity index 88%
rename from git/commit/git_total_commits_test_stub.go
rename to git/commit/stub/git_list_all_commit_logs_test_stub.go
index efe8052..6518b21 100644
--- a/git/commit/git_total_commits_test_stub.go
+++ b/git/commit/stub/git_list_all_commit_logs_test_stub.go
@@ -1,4 +1,4 @@
-package commit
+package stub
 
 import (
 	"errors"
@@ -11,6 +11,10 @@ type revWalkStub struct {
 	shouldIterateReturnError bool
 }
 
+func (w *revWalkStub) Push(id *git2go.Oid) error {
+	return nil
+}
+
 func (w *revWalkStub) PushHead() error {
 	return nil
 }

From d75a9ae015404c8625f1cf59f445428d0d29fc51 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 21 Jul 2021 00:00:03 +0530
Subject: [PATCH 059/148] update commit total api to use new list all commit
 logs api

---
 build_scripts/generate_all_mocks.sh    |  6 ----
 generate_all_mocks.sh                  |  7 ++++
 git/commit/git_total_commits.go        | 11 +++---
 git/commit/git_total_commits_test.go   | 33 +++++++----------
 mocks/mock_git_list_all_commit_logs.go | 50 ++++++++++++++++++++++++++
 5 files changed, 74 insertions(+), 33 deletions(-)
 delete mode 100755 build_scripts/generate_all_mocks.sh
 create mode 100755 generate_all_mocks.sh
 create mode 100644 mocks/mock_git_list_all_commit_logs.go

diff --git a/build_scripts/generate_all_mocks.sh b/build_scripts/generate_all_mocks.sh
deleted file mode 100755
index c88f602..0000000
--- a/build_scripts/generate_all_mocks.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-mockgen -source=../git/middleware/repository.go -destination=../mocks/mock_repository.go -package=mocks
-mockgen -source=../git/middleware/walk.go -destination=../mocks/mock_walk.go -package=mocks
-mockgen -source=../git/middleware/reference.go -destination=../mocks/mock_reference.go -package=mocks
-mockgen -source=../git/middleware/index.go -destination=../mocks/mock_index.go -package=mocks
\ No newline at end of file
diff --git a/generate_all_mocks.sh b/generate_all_mocks.sh
new file mode 100755
index 0000000..5aaaf94
--- /dev/null
+++ b/generate_all_mocks.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+mockgen -source=git/middleware/repository.go -destination=mocks/mock_repository.go -package=mocks
+mockgen -source=git/middleware/walk.go -destination=mocks/mock_walk.go -package=mocks
+mockgen -source=git/middleware/reference.go -destination=mocks/mock_reference.go -package=mocks
+mockgen -source=git/middleware/index.go -destination=mocks/mock_index.go -package=mocks
+mockgen -source=git/commit/git_list_all_commit_logs.go -destination=mocks/mock_git_list_all_commit_logs.go -package=mocks
\ No newline at end of file
diff --git a/git/commit/git_total_commits.go b/git/commit/git_total_commits.go
index 8162cec..d2a1eef 100644
--- a/git/commit/git_total_commits.go
+++ b/git/commit/git_total_commits.go
@@ -3,7 +3,6 @@ package commit
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 )
 
@@ -12,8 +11,7 @@ type Total interface {
 }
 
 type totalCommits struct {
-	repo    middleware.Repository
-	revWalk middleware.RevWalk
+	listAllLogs ListAllLogs
 }
 
 type commitType struct {
@@ -23,9 +21,8 @@ type commitType struct {
 // Get function returns the total number of commits from the repo and commit message of the most recent commit
 func (t totalCommits) Get() int {
 	var total = 0
-	repo := t.repo
+	allLogs := t.listAllLogs
 
-	allLogs := NewListAllLogs(repo)
 	commits, err := allLogs.Get()
 	if err != nil {
 		logger.Log(fmt.Sprintf("Unable to obtain commits for the repo : %v", err.Error()), global.StatusError)
@@ -42,6 +39,6 @@ func (t totalCommits) Get() int {
 	return total
 }
 
-func NewTotalCommits(repo middleware.Repository) Total {
-	return totalCommits{repo: repo}
+func NewTotalCommits(listAllLogs ListAllLogs) Total {
+	return totalCommits{listAllLogs: listAllLogs}
 }
diff --git a/git/commit/git_total_commits_test.go b/git/commit/git_total_commits_test.go
index 4c715ab..20965ce 100644
--- a/git/commit/git_total_commits_test.go
+++ b/git/commit/git_total_commits_test.go
@@ -15,13 +15,13 @@ import (
 
 type TotalCommitsTestSuite struct {
 	suite.Suite
-	mockController *gomock.Controller
-	total          Total
-	repo           middleware.Repository
-	mockRepo       *mocks.MockRepository
-	mockWalker     *mocks.MockRevWalk
-	noHeadRepo     *git2go.Repository
-	stub           middleware.RevWalk
+	mockController    *gomock.Controller
+	total             Total
+	repo              middleware.Repository
+	mockRepo          *mocks.MockRepository
+	mockWalker        *mocks.MockRevWalk
+	noHeadRepo        *git2go.Repository
+	mockAllCommitLogs *mocks.MockListAllLogs
 }
 
 func TestTotalCommitsTestSuite(t *testing.T) {
@@ -42,19 +42,20 @@ func (suite *TotalCommitsTestSuite) SetupTest() {
 	suite.noHeadRepo = noHeadRepo
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
 	suite.mockWalker = mocks.NewMockRevWalk(suite.mockController)
-	suite.total = NewTotalCommits(suite.mockRepo)
+	suite.mockAllCommitLogs = mocks.NewMockListAllLogs(suite.mockController)
+	suite.total = NewTotalCommits(suite.mockAllCommitLogs)
 }
 
 func (suite *TotalCommitsTestSuite) TestGet_WhenLogsAreAvailable_ShouldReturnTotal() {
-	suite.total = NewTotalCommits(suite.repo)
+	suite.mockAllCommitLogs.EXPECT().Get().Return([]git2go.Commit{{}, {}}, nil)
 
 	got := suite.total.Get()
 
 	suite.NotZero(got)
 }
 
-func (suite *TotalCommitsTestSuite) TestGet_WhenRepoWalkFails_ShouldReturnZero() {
-	suite.mockRepo.EXPECT().Walk().Return(nil, errors.New("WALKER_ERROR"))
+func (suite *TotalCommitsTestSuite) TestGet_WhenListLogReturnsError_ShouldReturnZero() {
+	suite.mockAllCommitLogs.EXPECT().Get().Return(nil, errors.New("LIST_ERROR"))
 
 	got := suite.total.Get()
 
@@ -62,15 +63,7 @@ func (suite *TotalCommitsTestSuite) TestGet_WhenRepoWalkFails_ShouldReturnZero()
 }
 
 func (suite *TotalCommitsTestSuite) TestGet_WhenRepoHasNoCommits_ShouldReturnZero() {
-	suite.mockRepo.EXPECT().Walk().Return(NewRevWalkStub(false), nil)
-
-	got := suite.total.Get()
-
-	suite.Zero(got)
-}
-
-func (suite *TotalCommitsTestSuite) TestGet_WhenIteratorReturnsError_ShouldReturnZero() {
-	suite.mockRepo.EXPECT().Walk().Return(NewRevWalkStub(true), nil)
+	suite.mockAllCommitLogs.EXPECT().Get().Return([]git2go.Commit{}, nil)
 
 	got := suite.total.Get()
 
diff --git a/mocks/mock_git_list_all_commit_logs.go b/mocks/mock_git_list_all_commit_logs.go
new file mode 100644
index 0000000..f0ac0ff
--- /dev/null
+++ b/mocks/mock_git_list_all_commit_logs.go
@@ -0,0 +1,50 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/commit/git_list_all_commit_logs.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockListAllLogs is a mock of ListAllLogs interface.
+type MockListAllLogs struct {
+	ctrl     *gomock.Controller
+	recorder *MockListAllLogsMockRecorder
+}
+
+// MockListAllLogsMockRecorder is the mock recorder for MockListAllLogs.
+type MockListAllLogsMockRecorder struct {
+	mock *MockListAllLogs
+}
+
+// NewMockListAllLogs creates a new mock instance.
+func NewMockListAllLogs(ctrl *gomock.Controller) *MockListAllLogs {
+	mock := &MockListAllLogs{ctrl: ctrl}
+	mock.recorder = &MockListAllLogsMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockListAllLogs) EXPECT() *MockListAllLogsMockRecorder {
+	return m.recorder
+}
+
+// Get mocks base method.
+func (m *MockListAllLogs) Get() ([]git.Commit, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Get")
+	ret0, _ := ret[0].([]git.Commit)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Get indicates an expected call of Get.
+func (mr *MockListAllLogsMockRecorder) Get() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockListAllLogs)(nil).Get))
+}

From b535cfe9e79c6f3776017986c2ac9665114a78ba Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 21 Jul 2021 23:30:39 +0530
Subject: [PATCH 060/148] update all commit logs api to return logs based on
 limit and commit reference

---
 git/commit/git_list_all_commit_logs.go      | 61 +++++++++++++++++++--
 git/commit/git_list_all_commit_logs_test.go | 31 ++++++++++-
 git/commit/git_total_commits.go             |  5 --
 git/middleware/walk.go                      |  5 ++
 mocks/mock_walk.go                          | 16 +++++-
 5 files changed, 104 insertions(+), 14 deletions(-)

diff --git a/git/commit/git_list_all_commit_logs.go b/git/commit/git_list_all_commit_logs.go
index 21d187b..b36daa6 100644
--- a/git/commit/git_list_all_commit_logs.go
+++ b/git/commit/git_list_all_commit_logs.go
@@ -12,7 +12,13 @@ type ListAllLogs interface {
 }
 
 type listAllLogs struct {
-	repo middleware.Repository
+	repo      middleware.Repository
+	limit     *uint
+	reference *git2go.Oid
+}
+
+type commitType struct {
+	commits []git2go.Commit
 }
 
 func (l listAllLogs) Get() ([]git2go.Commit, error) {
@@ -34,14 +40,41 @@ func (l listAllLogs) Get() ([]git2go.Commit, error) {
 }
 
 func (l listAllLogs) allCommitLogs(logItr middleware.RevWalk) ([]git2go.Commit, error) {
-	var c commitType
-	_ = logItr.PushHead()
+	var (
+		c commitType
+	)
+
+	pushErr := l.pushCommitReference(logItr)
+	if pushErr != nil {
+		logger.Log(pushErr.Error(), global.StatusError)
+		return nil, pushErr
+	}
 
-	err := logItr.Iterate(revIterator(&c))
+	err := l.iterate(logItr, &c)
 
 	return c.commits, err
 }
 
+func (l listAllLogs) iterate(logItr middleware.RevWalk, c *commitType) error {
+	if l.limit == nil {
+		logger.Log("Iterating commit logs without limit", global.StatusInfo)
+		return logItr.Iterate(revIterator(c))
+	}
+
+	logger.Log(fmt.Sprintf("Iterating commit logs with limit %v", *l.limit), global.StatusInfo)
+	return logItr.Iterate(revIteratorWithLimit(c, *l.limit))
+}
+
+func (l listAllLogs) pushCommitReference(logItr middleware.RevWalk) error {
+	if l.reference != nil {
+		logger.Log(fmt.Sprintf("Iterating commits from reference %s", l.reference), global.StatusInfo)
+		return logItr.Push(l.reference)
+	}
+
+	logger.Log(fmt.Sprintf("Iterating commits from HEAD"), global.StatusInfo)
+	return logItr.PushHead()
+}
+
 func revIterator(c *commitType) git2go.RevWalkIterator {
 	return func(commit *git2go.Commit) bool {
 		if commit != nil {
@@ -53,8 +86,24 @@ func revIterator(c *commitType) git2go.RevWalkIterator {
 	}
 }
 
-func NewListAllLogs(repo middleware.Repository) ListAllLogs {
+func revIteratorWithLimit(c *commitType, limit uint) git2go.RevWalkIterator {
+	var commitCounter uint
+
+	return func(commit *git2go.Commit) bool {
+		if commit != nil && commitCounter < limit {
+			c.commits = append(c.commits, *commit)
+			commitCounter++
+			return true
+		}
+
+		return false
+	}
+}
+
+func NewListAllLogs(repo middleware.Repository, limit *uint, reference *git2go.Oid) ListAllLogs {
 	return listAllLogs{
-		repo: repo,
+		repo:      repo,
+		limit:     limit,
+		reference: reference,
 	}
 }
diff --git a/git/commit/git_list_all_commit_logs_test.go b/git/commit/git_list_all_commit_logs_test.go
index 1b8af19..b5c2a74 100644
--- a/git/commit/git_list_all_commit_logs_test.go
+++ b/git/commit/git_list_all_commit_logs_test.go
@@ -19,6 +19,7 @@ type ListAllCommitLogsTestSuite struct {
 	mockRepo          *mocks.MockRepository
 	mockRevWalk       *mocks.MockRevWalk
 	repo              middleware.Repository
+	totalCommits      Total
 	listAllCommitLogs ListAllLogs
 }
 
@@ -37,17 +38,43 @@ func (suite *ListAllCommitLogsTestSuite) SetupTest() {
 	}
 
 	suite.repo = middleware.NewRepository(r)
-	suite.listAllCommitLogs = NewListAllLogs(suite.mockRepo)
+	suite.listAllCommitLogs = NewListAllLogs(suite.mockRepo, nil, nil)
+	suite.totalCommits = NewTotalCommits(NewListAllLogs(suite.repo, nil, nil))
 }
 
 func (suite *ListAllCommitLogsTestSuite) TestGet_WhenLogsAreAvailable_ShouldReturnCommitLogs() {
-	suite.listAllCommitLogs = NewListAllLogs(suite.repo)
+	suite.listAllCommitLogs = NewListAllLogs(suite.repo, nil, nil)
 	got, err := suite.listAllCommitLogs.Get()
 
 	suite.NotZero(len(got))
 	suite.Nil(err)
 }
 
+func (suite *ListAllCommitLogsTestSuite) TestGet_WhenLogLimitIsGiven_ShouldReturnCommitLogsUptoLimit() {
+	var limit uint = 3
+
+	suite.listAllCommitLogs = NewListAllLogs(suite.repo, &limit, nil)
+	got, err := suite.listAllCommitLogs.Get()
+
+	suite.Equal(int(limit), len(got))
+	suite.Nil(err)
+}
+
+func (suite *ListAllCommitLogsTestSuite) TestGet_WhenReferenceIsGiven_ShouldReturnCommitLogsAfterTheReference() {
+	var limit uint = 3
+
+	commits, _ := NewListAllLogs(suite.repo, &limit, nil).Get()
+	commitId, _ := git2go.NewOid(commits[limit-1].Id().String())
+	total := suite.totalCommits.Get()
+
+	suite.listAllCommitLogs = NewListAllLogs(suite.repo, nil, commitId)
+	got, err := suite.listAllCommitLogs.Get()
+	want := total - (int(limit) - 1)
+
+	suite.Equal(want, len(got))
+	suite.Nil(err)
+}
+
 func (suite *ListAllCommitLogsTestSuite) TestGet_WhenRepoWalkFails_ShouldReturnError() {
 	suite.mockRepo.EXPECT().Walk().Return(nil, errors.New("WALKER_ERROR"))
 
diff --git a/git/commit/git_total_commits.go b/git/commit/git_total_commits.go
index d2a1eef..5ab36ff 100644
--- a/git/commit/git_total_commits.go
+++ b/git/commit/git_total_commits.go
@@ -2,7 +2,6 @@ package commit
 
 import (
 	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
 )
 
@@ -14,10 +13,6 @@ type totalCommits struct {
 	listAllLogs ListAllLogs
 }
 
-type commitType struct {
-	commits []git2go.Commit
-}
-
 // Get function returns the total number of commits from the repo and commit message of the most recent commit
 func (t totalCommits) Get() int {
 	var total = 0
diff --git a/git/middleware/walk.go b/git/middleware/walk.go
index ea2fe37..fcb76d4 100644
--- a/git/middleware/walk.go
+++ b/git/middleware/walk.go
@@ -5,12 +5,17 @@ import git "github.com/libgit2/git2go/v31"
 type RevWalk interface {
 	Iterate(iterator git.RevWalkIterator) error
 	PushHead() error
+	Push(id *git.Oid) error
 }
 
 type revWalk struct {
 	walk *git.RevWalk
 }
 
+func (w *revWalk) Push(id *git.Oid) error {
+	return w.walk.Push(id)
+}
+
 func (w *revWalk) PushHead() error {
 	return w.walk.PushHead()
 }
diff --git a/mocks/mock_walk.go b/mocks/mock_walk.go
index 4425076..bc607c7 100644
--- a/mocks/mock_walk.go
+++ b/mocks/mock_walk.go
@@ -1,5 +1,5 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: ../git/middleware/walk.go
+// Source: git/middleware/walk.go
 
 // Package mocks is a generated GoMock package.
 package mocks
@@ -48,6 +48,20 @@ func (mr *MockRevWalkMockRecorder) Iterate(iterator interface{}) *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterate", reflect.TypeOf((*MockRevWalk)(nil).Iterate), iterator)
 }
 
+// Push mocks base method.
+func (m *MockRevWalk) Push(id *git.Oid) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Push", id)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Push indicates an expected call of Push.
+func (mr *MockRevWalkMockRecorder) Push(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Push", reflect.TypeOf((*MockRevWalk)(nil).Push), id)
+}
+
 // PushHead mocks base method.
 func (m *MockRevWalk) PushHead() error {
 	m.ctrl.T.Helper()

From af320ef230d9a52c8866dde14a17124d26cfc24f Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 23 Jul 2021 23:59:36 +0530
Subject: [PATCH 061/148] add new commit file history api

---
 constants/errors.go                        | 37 ++++-----
 git/commit/git_commit_file_history.go      | 88 ++++++++++++++++++++++
 git/commit/git_commit_file_history_test.go | 48 ++++++++++++
 mocks/mock_repository.go                   | 17 ++++-
 4 files changed, 171 insertions(+), 19 deletions(-)
 create mode 100644 git/commit/git_commit_file_history.go
 create mode 100644 git/commit/git_commit_file_history_test.go

diff --git a/constants/errors.go b/constants/errors.go
index 52a7c1c..abf4706 100644
--- a/constants/errors.go
+++ b/constants/errors.go
@@ -7,24 +7,25 @@ type ApiError struct {
 }
 
 var (
-	BranchAddError       = ApiError{ErrorCode: "BRANCH_ADD_FAILED", ErrorString: "Failed to add new branch"}
-	BranchCheckoutError  = ApiError{ErrorCode: "CHECKOUT_FAILED", ErrorString: "Failed to checkout branch"}
-	BranchDeleteError    = ApiError{ErrorCode: "BRANCH_DELETE_FAILED", ErrorString: "Failed to delete branch"}
-	RemoteAddError       = ApiError{ErrorCode: "REMOTE_ADD_FAILED", ErrorString: "Failed to delete add new remote"}
-	RemoteDeleteError    = ApiError{ErrorCode: "REMOTE_DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
-	RemoteEditError      = ApiError{ErrorCode: "REMOTE_EDIT_FAILED", ErrorString: "Failed to delete add new remote"}
-	FetchFromRemoteError = ApiError{ErrorCode: "FETCH_ERROR", ErrorString: "Failed to delete add new remote"}
-	PullFromRemoteError  = ApiError{ErrorCode: "PULL_ERROR", ErrorString: "Failed to delete add new remote"}
-	StageItemError       = ApiError{ErrorCode: "ADD_ITEM_FAILED", ErrorString: "Failed to delete add new remote"}
-	StageAllItemsError   = ApiError{ErrorCode: "ALL_STAGE_FAILED", ErrorString: "Failed to delete add new remote"}
-	RemoveItemError      = ApiError{ErrorCode: "STAGE_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
-	RemoveAllItemsError  = ApiError{ErrorCode: "STAGE_ALL_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
-	CommitChangeError    = ApiError{ErrorCode: "COMMIT_FAILED", ErrorString: "Failed to delete add new remote"}
-	PushToRemoteError    = ApiError{ErrorCode: "PUSH_FAILED", ErrorString: "Failed to delete add new remote"}
-	PortUpdateError      = ApiError{ErrorCode: "PORT_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
-	DataFileUpdateError  = ApiError{ErrorCode: "DATAFILE_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
-	RepoDeleteError      = ApiError{ErrorCode: "DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
-	CommitLogsError      = ApiError{ErrorCode: "LIST_COMMIT_LOGS_FAILED", ErrorString: "Failed to delete add new remote"}
+	BranchAddError         = ApiError{ErrorCode: "BRANCH_ADD_FAILED", ErrorString: "Failed to add new branch"}
+	BranchCheckoutError    = ApiError{ErrorCode: "CHECKOUT_FAILED", ErrorString: "Failed to checkout branch"}
+	BranchDeleteError      = ApiError{ErrorCode: "BRANCH_DELETE_FAILED", ErrorString: "Failed to delete branch"}
+	RemoteAddError         = ApiError{ErrorCode: "REMOTE_ADD_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoteDeleteError      = ApiError{ErrorCode: "REMOTE_DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoteEditError        = ApiError{ErrorCode: "REMOTE_EDIT_FAILED", ErrorString: "Failed to delete add new remote"}
+	FetchFromRemoteError   = ApiError{ErrorCode: "FETCH_ERROR", ErrorString: "Failed to delete add new remote"}
+	PullFromRemoteError    = ApiError{ErrorCode: "PULL_ERROR", ErrorString: "Failed to delete add new remote"}
+	StageItemError         = ApiError{ErrorCode: "ADD_ITEM_FAILED", ErrorString: "Failed to delete add new remote"}
+	StageAllItemsError     = ApiError{ErrorCode: "ALL_STAGE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoveItemError        = ApiError{ErrorCode: "STAGE_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoveAllItemsError    = ApiError{ErrorCode: "STAGE_ALL_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
+	CommitChangeError      = ApiError{ErrorCode: "COMMIT_FAILED", ErrorString: "Failed to delete add new remote"}
+	PushToRemoteError      = ApiError{ErrorCode: "PUSH_FAILED", ErrorString: "Failed to delete add new remote"}
+	PortUpdateError        = ApiError{ErrorCode: "PORT_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
+	DataFileUpdateError    = ApiError{ErrorCode: "DATAFILE_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RepoDeleteError        = ApiError{ErrorCode: "DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
+	CommitLogsError        = ApiError{ErrorCode: "LIST_COMMIT_LOGS_FAILED", ErrorString: "Failed to delete add new remote"}
+	CommitFileHistoryError = ApiError{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_FAILED", ErrorString: "Failed to get the list of file changes for the commit"}
 )
 
 func (e ApiError) Error() string {
diff --git a/git/commit/git_commit_file_history.go b/git/commit/git_commit_file_history.go
new file mode 100644
index 0000000..8b1a0ac
--- /dev/null
+++ b/git/commit/git_commit_file_history.go
@@ -0,0 +1,88 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/constants"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type FileHistory interface {
+	Get(*git2go.Commit) ([]*model.GitCommitFileResult, error)
+}
+
+type fileHistory struct {
+	repo middleware.Repository
+}
+
+func (f fileHistory) Get(commit *git2go.Commit) ([]*model.GitCommitFileResult, error) {
+	commitHash := commit.Id().String()
+
+	logger.Log(fmt.Sprintf("Fetching file details for commit %v", commitHash), global.StatusInfo)
+
+	prevTree, commitTree, treeErr := f.treesOf(commit)
+	if treeErr != nil {
+		return fileHistoryError(treeErr)
+	}
+
+	return f.diffBetweenTrees(prevTree, commitTree)
+}
+
+func (f fileHistory) diffBetweenTrees(previousTree *git2go.Tree, currentTree *git2go.Tree) ([]*model.GitCommitFileResult, error) {
+	var history []*model.GitCommitFileResult
+
+	logger.Log("Checking diff between trees", global.StatusInfo)
+	diff, diffErr := f.repo.DiffTreeToTree(previousTree, currentTree, nil)
+	if diffErr != nil {
+		return fileHistoryError(diffErr)
+	}
+
+	numDelta, numDeltaErr := diff.NumDeltas()
+	if numDeltaErr != nil {
+		return fileHistoryError(numDeltaErr)
+	}
+
+	for d := 0; d < numDelta; d++ {
+		delta, _ := diff.Delta(d)
+		status := delta.Status.String()
+		history = append(history, &model.GitCommitFileResult{
+			Type:     status[0:1],
+			FileName: delta.NewFile.Path,
+		})
+	}
+
+	fmt.Println(numDelta, history)
+	return history, nil
+}
+
+func (f fileHistory) treesOf(commit *git2go.Commit) (*git2go.Tree, *git2go.Tree, error) {
+	var treeErr error
+	logger.Log("Getting current and previous trees", global.StatusInfo)
+
+	parents := commit.ParentCount()
+	if parents == 0 {
+		return nil, nil, errors.New("commit has no parents")
+	}
+
+	previousCommit := commit.Parent(0)
+
+	previousTree, treeErr := previousCommit.Tree()
+	currentTree, treeErr := commit.Tree()
+	if treeErr != nil {
+		return nil, nil, treeErr
+	}
+
+	return previousTree, currentTree, nil
+}
+
+func fileHistoryError(err error) ([]*model.GitCommitFileResult, error) {
+	logger.Log(err.Error(), global.StatusError)
+	return nil, constants.CommitFileHistoryError
+}
+
+func NewFileHistory(repo middleware.Repository) FileHistory {
+	return fileHistory{repo: repo}
+}
diff --git a/git/commit/git_commit_file_history_test.go b/git/commit/git_commit_file_history_test.go
new file mode 100644
index 0000000..5647353
--- /dev/null
+++ b/git/commit/git_commit_file_history_test.go
@@ -0,0 +1,48 @@
+package commit
+
+import (
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type FileHistoryTestSuite struct {
+	suite.Suite
+	mockController *gomock.Controller
+	repo           middleware.Repository
+	mockRepo       *mocks.MockRepository
+	fileHistory    FileHistory
+}
+
+func TestFileHistoryTestSuite(t *testing.T) {
+	suite.Run(t, new(FileHistoryTestSuite))
+}
+
+func (suite *FileHistoryTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.mockController = gomock.NewController(suite.T())
+	suite.repo = middleware.NewRepository(r)
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.fileHistory = NewFileHistory(suite.mockRepo)
+}
+
+func (suite *FileHistoryTestSuite) TestGet_WhenRepoHasMoreThanOneCommit_ShouldReturnDiffForChosenCommit() {
+	suite.fileHistory = NewFileHistory(suite.repo)
+
+	head, _ := suite.repo.Head()
+	commit, _ := suite.repo.LookupCommit(head.Target())
+
+	gotHistory, err := suite.fileHistory.Get(commit)
+
+	suite.Nil(err)
+	suite.NotZero(len(gotHistory))
+}
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
index e0ac746..5beb725 100644
--- a/mocks/mock_repository.go
+++ b/mocks/mock_repository.go
@@ -1,5 +1,5 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: ../git/middleware/repository.go
+// Source: git/middleware/repository.go
 
 // Package mocks is a generated GoMock package.
 package mocks
@@ -70,6 +70,21 @@ func (mr *MockRepositoryMockRecorder) DefaultSignature() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultSignature", reflect.TypeOf((*MockRepository)(nil).DefaultSignature))
 }
 
+// DiffTreeToTree mocks base method.
+func (m *MockRepository) DiffTreeToTree(tree, tree2 *git.Tree, options *git.DiffOptions) (*git.Diff, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DiffTreeToTree", tree, tree2, options)
+	ret0, _ := ret[0].(*git.Diff)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// DiffTreeToTree indicates an expected call of DiffTreeToTree.
+func (mr *MockRepositoryMockRecorder) DiffTreeToTree(tree, tree2, options interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DiffTreeToTree", reflect.TypeOf((*MockRepository)(nil).DiffTreeToTree), tree, tree2, options)
+}
+
 // Head mocks base method.
 func (m *MockRepository) Head() (middleware.Reference, error) {
 	m.ctrl.T.Helper()

From 8ff2e6e9479c7d226c10c4d98d5f26e876bb816b Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 24 Jul 2021 23:31:04 +0530
Subject: [PATCH 062/148] update file history api test with new mocks

---
 generate_all_mocks.sh                      |  3 +-
 git/commit/commit.go                       |  6 +-
 git/commit/errors.go                       | 19 +++++++
 git/commit/git_commit_file_history.go      | 56 ++++++++++---------
 git/commit/git_commit_file_history_test.go | 65 +++++++++++++++++++++-
 git/middleware/commit.go                   | 34 +++++++++++
 git/middleware/repository.go               |  5 ++
 mocks/mock_index.go                        |  2 +-
 mocks/mock_reference.go                    |  2 +-
 9 files changed, 159 insertions(+), 33 deletions(-)
 create mode 100644 git/commit/errors.go
 create mode 100644 git/middleware/commit.go

diff --git a/generate_all_mocks.sh b/generate_all_mocks.sh
index 5aaaf94..7e404d7 100755
--- a/generate_all_mocks.sh
+++ b/generate_all_mocks.sh
@@ -4,4 +4,5 @@ mockgen -source=git/middleware/repository.go -destination=mocks/mock_repository.
 mockgen -source=git/middleware/walk.go -destination=mocks/mock_walk.go -package=mocks
 mockgen -source=git/middleware/reference.go -destination=mocks/mock_reference.go -package=mocks
 mockgen -source=git/middleware/index.go -destination=mocks/mock_index.go -package=mocks
-mockgen -source=git/commit/git_list_all_commit_logs.go -destination=mocks/mock_git_list_all_commit_logs.go -package=mocks
\ No newline at end of file
+mockgen -source=git/commit/git_list_all_commit_logs.go -destination=mocks/mock_git_list_all_commit_logs.go -package=mocks
+mockgen -source=git/middleware/commit.go -destination=mocks/mock_commit.go -package=mocks
\ No newline at end of file
diff --git a/git/commit/commit.go b/git/commit/commit.go
index 28abbec..73726c8 100644
--- a/git/commit/commit.go
+++ b/git/commit/commit.go
@@ -1,6 +1,8 @@
 package commit
 
-import "github.com/neel1996/gitconvex/global"
+import (
+	"github.com/neel1996/gitconvex/global"
+)
 
 var logger global.Logger
 
@@ -18,7 +20,7 @@ func (c Operation) GitCommitChange() (string, error) {
 
 	if err != nil {
 		logger.Log(err.Error(), global.StatusError)
-		return global.CommitChangeError, err
+		return "", CommitLogsError
 	}
 
 	return global.CommitChangeSuccess, nil
diff --git a/git/commit/errors.go b/git/commit/errors.go
new file mode 100644
index 0000000..c85e003
--- /dev/null
+++ b/git/commit/errors.go
@@ -0,0 +1,19 @@
+package commit
+
+type Error struct {
+	error
+	ErrorCode   string
+	ErrorString string
+}
+
+var (
+	CommitChangeError              = Error{ErrorCode: "COMMIT_FAILED", ErrorString: "Failed to delete add new remote"}
+	CommitLogsError                = Error{ErrorCode: "LIST_COMMIT_LOGS_FAILED", ErrorString: "Failed to delete add new remote"}
+	CommitFileHistoryError         = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_FAILED", ErrorString: "Failed to get the list of file changes for the commit"}
+	CommitFileHistoryNoParentError = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_NO_PARENT", ErrorString: "The HEAD commit is the only commit in the repo and has no previous histories"}
+	CommitFileHistoryTreeError     = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_INVALID_TREE", ErrorString: "The commit tree is invalid"}
+)
+
+func (e Error) Error() string {
+	return e.ErrorString
+}
diff --git a/git/commit/git_commit_file_history.go b/git/commit/git_commit_file_history.go
index 8b1a0ac..1316f5f 100644
--- a/git/commit/git_commit_file_history.go
+++ b/git/commit/git_commit_file_history.go
@@ -1,26 +1,24 @@
 package commit
 
 import (
-	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/constants"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
+	"reflect"
 )
 
 type FileHistory interface {
-	Get(*git2go.Commit) ([]*model.GitCommitFileResult, error)
+	Get(commit middleware.Commit) ([]*model.GitCommitFileResult, error)
 }
 
 type fileHistory struct {
 	repo middleware.Repository
 }
 
-func (f fileHistory) Get(commit *git2go.Commit) ([]*model.GitCommitFileResult, error) {
+func (f fileHistory) Get(commit middleware.Commit) ([]*model.GitCommitFileResult, error) {
 	commitHash := commit.Id().String()
-
 	logger.Log(fmt.Sprintf("Fetching file details for commit %v", commitHash), global.StatusInfo)
 
 	prevTree, commitTree, treeErr := f.treesOf(commit)
@@ -31,6 +29,28 @@ func (f fileHistory) Get(commit *git2go.Commit) ([]*model.GitCommitFileResult, e
 	return f.diffBetweenTrees(prevTree, commitTree)
 }
 
+func (f fileHistory) treesOf(commit middleware.Commit) (*git2go.Tree, *git2go.Tree, error) {
+	var treeErr error
+	logger.Log("Getting current and previous trees", global.StatusInfo)
+
+	parents := commit.ParentCount()
+	if parents == 0 {
+		logger.Log("Commit has no parent", global.StatusError)
+		return nil, nil, CommitFileHistoryNoParentError
+	}
+
+	previousCommit := commit.Parent(0)
+
+	previousTree, treeErr := previousCommit.Tree()
+	currentTree, treeErr := commit.Tree()
+	if treeErr != nil {
+		logger.Log(treeErr.Error(), global.StatusError)
+		return nil, nil, CommitFileHistoryTreeError
+	}
+
+	return previousTree, currentTree, nil
+}
+
 func (f fileHistory) diffBetweenTrees(previousTree *git2go.Tree, currentTree *git2go.Tree) ([]*model.GitCommitFileResult, error) {
 	var history []*model.GitCommitFileResult
 
@@ -54,33 +74,15 @@ func (f fileHistory) diffBetweenTrees(previousTree *git2go.Tree, currentTree *gi
 		})
 	}
 
-	fmt.Println(numDelta, history)
 	return history, nil
 }
 
-func (f fileHistory) treesOf(commit *git2go.Commit) (*git2go.Tree, *git2go.Tree, error) {
-	var treeErr error
-	logger.Log("Getting current and previous trees", global.StatusInfo)
-
-	parents := commit.ParentCount()
-	if parents == 0 {
-		return nil, nil, errors.New("commit has no parents")
-	}
-
-	previousCommit := commit.Parent(0)
-
-	previousTree, treeErr := previousCommit.Tree()
-	currentTree, treeErr := commit.Tree()
-	if treeErr != nil {
-		return nil, nil, treeErr
-	}
-
-	return previousTree, currentTree, nil
-}
-
 func fileHistoryError(err error) ([]*model.GitCommitFileResult, error) {
 	logger.Log(err.Error(), global.StatusError)
-	return nil, constants.CommitFileHistoryError
+	if reflect.TypeOf(err) != reflect.TypeOf(Error{}) {
+		return nil, CommitFileHistoryError
+	}
+	return nil, err
 }
 
 func NewFileHistory(repo middleware.Repository) FileHistory {
diff --git a/git/commit/git_commit_file_history_test.go b/git/commit/git_commit_file_history_test.go
index 5647353..59dbd48 100644
--- a/git/commit/git_commit_file_history_test.go
+++ b/git/commit/git_commit_file_history_test.go
@@ -1,6 +1,7 @@
 package commit
 
 import (
+	"errors"
 	"fmt"
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
@@ -16,6 +17,7 @@ type FileHistoryTestSuite struct {
 	mockController *gomock.Controller
 	repo           middleware.Repository
 	mockRepo       *mocks.MockRepository
+	mockCommit     *mocks.MockCommit
 	fileHistory    FileHistory
 }
 
@@ -32,6 +34,7 @@ func (suite *FileHistoryTestSuite) SetupTest() {
 	suite.mockController = gomock.NewController(suite.T())
 	suite.repo = middleware.NewRepository(r)
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
 	suite.fileHistory = NewFileHistory(suite.mockRepo)
 }
 
@@ -41,8 +44,68 @@ func (suite *FileHistoryTestSuite) TestGet_WhenRepoHasMoreThanOneCommit_ShouldRe
 	head, _ := suite.repo.Head()
 	commit, _ := suite.repo.LookupCommit(head.Target())
 
-	gotHistory, err := suite.fileHistory.Get(commit)
+	gotHistory, err := suite.fileHistory.Get(middleware.NewCommit(commit))
 
 	suite.Nil(err)
 	suite.NotZero(len(gotHistory))
 }
+
+func (suite *FileHistoryTestSuite) TestGet_WhenCommitIsTheFirstCommitWithNoParents_ShouldReturnNoParentError() {
+	oid, _ := git2go.NewOid("5e0c30593a8819a05135f908e1729278d3ee086e")
+
+	suite.mockCommit.EXPECT().Id().Return(oid)
+	suite.mockCommit.EXPECT().ParentCount().Return(uint(0))
+
+	_, err := suite.fileHistory.Get(suite.mockCommit)
+
+	suite.NotNil(err)
+	suite.Equal(CommitFileHistoryNoParentError, err)
+}
+
+func (suite *FileHistoryTestSuite) TestGet_WhenCommitTreeIsInvalid_ShouldReturnTreeError() {
+	oid, _ := git2go.NewOid("5e0c30593a8819a05135f908e1729278d3ee086e")
+
+	suite.mockCommit.EXPECT().Id().Return(oid)
+	suite.mockCommit.EXPECT().ParentCount().Return(uint(1))
+	suite.mockCommit.EXPECT().Parent(uint(0)).Return(suite.mockCommit)
+	suite.mockCommit.EXPECT().Tree().Return(nil, errors.New("TREE_ERROR")).Times(2)
+
+	_, err := suite.fileHistory.Get(suite.mockCommit)
+
+	suite.NotNil(err)
+	suite.Equal(CommitFileHistoryTreeError, err)
+}
+
+func (suite *FileHistoryTestSuite) TestGet_WhenDiffTreeFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("5e0c30593a8819a05135f908e1729278d3ee086e")
+	treePtr := &git2go.Tree{Object: git2go.Object{}}
+
+	suite.mockCommit.EXPECT().Id().Return(oid)
+	suite.mockCommit.EXPECT().ParentCount().Return(uint(1))
+	suite.mockCommit.EXPECT().Parent(uint(0)).Return(suite.mockCommit)
+	suite.mockCommit.EXPECT().Tree().Return(treePtr, nil).Times(2)
+
+	suite.mockRepo.EXPECT().DiffTreeToTree(treePtr, treePtr, nil).Return(nil, errors.New("DIFF_ERROR"))
+
+	_, err := suite.fileHistory.Get(suite.mockCommit)
+
+	suite.NotNil(err)
+	suite.Equal(CommitFileHistoryError, err)
+}
+
+func (suite *FileHistoryTestSuite) TestGet_WhenDiffNumDeltaIsZero_ShouldReturnError() {
+	oid, _ := git2go.NewOid("5e0c30593a8819a05135f908e1729278d3ee086e")
+	treePtr := &git2go.Tree{Object: git2go.Object{}}
+
+	suite.mockCommit.EXPECT().Id().Return(oid)
+	suite.mockCommit.EXPECT().ParentCount().Return(uint(1))
+	suite.mockCommit.EXPECT().Parent(uint(0)).Return(suite.mockCommit)
+	suite.mockCommit.EXPECT().Tree().Return(treePtr, nil).Times(2)
+
+	suite.mockRepo.EXPECT().DiffTreeToTree(treePtr, treePtr, nil).Return(&git2go.Diff{}, nil)
+
+	_, err := suite.fileHistory.Get(suite.mockCommit)
+
+	suite.NotNil(err)
+	suite.Equal(CommitFileHistoryError, err)
+}
diff --git a/git/middleware/commit.go b/git/middleware/commit.go
new file mode 100644
index 0000000..6739a09
--- /dev/null
+++ b/git/middleware/commit.go
@@ -0,0 +1,34 @@
+package middleware
+
+import git "github.com/libgit2/git2go/v31"
+
+type Commit interface {
+	ParentCount() uint
+	Id() *git.Oid
+	Parent(uint) Commit
+	Tree() (*git.Tree, error)
+}
+
+type commit struct {
+	gitCommit *git.Commit
+}
+
+func (c commit) Tree() (*git.Tree, error) {
+	return c.gitCommit.Tree()
+}
+
+func (c commit) Parent(i uint) Commit {
+	return NewCommit(c.gitCommit.Parent(i))
+}
+
+func (c commit) Id() *git.Oid {
+	return c.gitCommit.Id()
+}
+
+func (c commit) ParentCount() uint {
+	return c.gitCommit.ParentCount()
+}
+
+func NewCommit(gitCommit *git.Commit) Commit {
+	return commit{gitCommit: gitCommit}
+}
diff --git a/git/middleware/repository.go b/git/middleware/repository.go
index cb82ef9..f2b8566 100644
--- a/git/middleware/repository.go
+++ b/git/middleware/repository.go
@@ -10,6 +10,7 @@ type Repository interface {
 	LookupTree(id *git.Oid) (*git.Tree, error)
 	Index() (Index, error)
 	CreateCommit(s string, signature *git.Signature, signature2 *git.Signature, message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error)
+	DiffTreeToTree(tree *git.Tree, tree2 *git.Tree, options *git.DiffOptions) (*git.Diff, error)
 }
 
 type repository struct {
@@ -55,6 +56,10 @@ func (r repository) LookupTree(id *git.Oid) (*git.Tree, error) {
 	return r.repo.LookupTree(id)
 }
 
+func (r repository) DiffTreeToTree(tree *git.Tree, tree2 *git.Tree, options *git.DiffOptions) (*git.Diff, error) {
+	return r.repo.DiffTreeToTree(tree, tree2, options)
+}
+
 func NewRepository(repo *git.Repository) Repository {
 	return repository{repo: repo}
 }
diff --git a/mocks/mock_index.go b/mocks/mock_index.go
index 4405b23..f6a5064 100644
--- a/mocks/mock_index.go
+++ b/mocks/mock_index.go
@@ -1,5 +1,5 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: ../git/middleware/index.go
+// Source: git/middleware/index.go
 
 // Package mocks is a generated GoMock package.
 package mocks
diff --git a/mocks/mock_reference.go b/mocks/mock_reference.go
index 730eb0c..95e329d 100644
--- a/mocks/mock_reference.go
+++ b/mocks/mock_reference.go
@@ -1,5 +1,5 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: ../git/middleware/reference.go
+// Source: git/middleware/reference.go
 
 // Package mocks is a generated GoMock package.
 package mocks

From 4ea944bc78d6286bf32df5f1e3f44ca3dc949877 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 26 Jul 2021 23:32:07 +0530
Subject: [PATCH 063/148] create new mapper to bind commit log api responses to
 the combined model

---
 generate_all_mocks.sh                    |  3 +-
 git/commit/git_commit_log_mapper.go      | 79 ++++++++++++++++++++
 git/commit/git_commit_log_mapper_test.go | 86 ++++++++++++++++++++++
 mocks/mock_commit.go                     | 93 ++++++++++++++++++++++++
 mocks/mock_git_commit_file_history.go    | 51 +++++++++++++
 5 files changed, 311 insertions(+), 1 deletion(-)
 create mode 100644 git/commit/git_commit_log_mapper.go
 create mode 100644 git/commit/git_commit_log_mapper_test.go
 create mode 100644 mocks/mock_commit.go
 create mode 100644 mocks/mock_git_commit_file_history.go

diff --git a/generate_all_mocks.sh b/generate_all_mocks.sh
index 7e404d7..fa0c14a 100755
--- a/generate_all_mocks.sh
+++ b/generate_all_mocks.sh
@@ -5,4 +5,5 @@ mockgen -source=git/middleware/walk.go -destination=mocks/mock_walk.go -package=
 mockgen -source=git/middleware/reference.go -destination=mocks/mock_reference.go -package=mocks
 mockgen -source=git/middleware/index.go -destination=mocks/mock_index.go -package=mocks
 mockgen -source=git/commit/git_list_all_commit_logs.go -destination=mocks/mock_git_list_all_commit_logs.go -package=mocks
-mockgen -source=git/middleware/commit.go -destination=mocks/mock_commit.go -package=mocks
\ No newline at end of file
+mockgen -source=git/middleware/commit.go -destination=mocks/mock_commit.go -package=mocks
+mockgen -source=git/commit/git_commit_file_history.go -destination=mocks/mock_git_commit_file_history.go -package=mocks
\ No newline at end of file
diff --git a/git/commit/git_commit_log_mapper.go b/git/commit/git_commit_log_mapper.go
new file mode 100644
index 0000000..e64ae70
--- /dev/null
+++ b/git/commit/git_commit_log_mapper.go
@@ -0,0 +1,79 @@
+package commit
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+	"strings"
+)
+
+type Mapper interface {
+	Map([]git2go.Commit) []*model.GitCommits
+}
+
+type mapper struct {
+	repo        middleware.Repository
+	fileHistory FileHistory
+}
+
+type mapperCommitType struct {
+	hash       *string
+	author     *string
+	commitTime *string
+	message    *string
+	filesCount *int
+}
+
+func (m mapper) Map(commits []git2go.Commit) []*model.GitCommits {
+	var mappedCommits []*model.GitCommits
+
+	for _, commit := range commits {
+		commitFields := m.commitFields(commit)
+
+		mappedCommits = append(mappedCommits, &model.GitCommits{
+			Hash:             commitFields.hash,
+			Author:           commitFields.author,
+			CommitTime:       commitFields.commitTime,
+			CommitMessage:    commitFields.message,
+			CommitFilesCount: commitFields.filesCount,
+		})
+	}
+
+	return mappedCommits
+}
+
+func (m mapper) commitFields(commit git2go.Commit) mapperCommitType {
+	commitHash := commit.Id().String()
+	commitAuthor := strings.Split(commit.Author().Name, " ")[0]
+	commitMessage := strings.Split(commit.Message(), "\n")[0]
+	commitDate := commit.Committer().When.String()
+	commitFileHistory := m.commitFileHistory(commit)
+
+	commitFields := mapperCommitType{
+		hash:       &commitHash,
+		author:     &commitAuthor,
+		commitTime: &commitDate,
+		message:    &commitMessage,
+		filesCount: &commitFileHistory,
+	}
+	return commitFields
+}
+
+func (m mapper) commitFileHistory(commit git2go.Commit) int {
+	c := middleware.NewCommit(&commit)
+	fileHistory, err := m.fileHistory.Get(c)
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return 0
+	}
+
+	return len(fileHistory)
+}
+
+func NewMapper(repo middleware.Repository, commitFile FileHistory) Mapper {
+	return mapper{
+		repo:        repo,
+		fileHistory: commitFile,
+	}
+}
diff --git a/git/commit/git_commit_log_mapper_test.go b/git/commit/git_commit_log_mapper_test.go
new file mode 100644
index 0000000..612f626
--- /dev/null
+++ b/git/commit/git_commit_log_mapper_test.go
@@ -0,0 +1,86 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"strings"
+	"testing"
+)
+
+type CommitLogMapperTestSuite struct {
+	suite.Suite
+	mockController  *gomock.Controller
+	repo            middleware.Repository
+	mockRepo        *mocks.MockRepository
+	fileHistory     FileHistory
+	mockFileHistory *mocks.MockFileHistory
+	commits         []git2go.Commit
+	mapper          Mapper
+}
+
+func TestCommitLogMapperTestSuite(t *testing.T) {
+	suite.Run(t, new(CommitLogMapperTestSuite))
+}
+
+func (suite *CommitLogMapperTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = middleware.NewRepository(r)
+
+	limit := uint(3)
+	commits, _ := NewListAllLogs(suite.repo, &limit, nil).Get()
+	suite.commits = commits
+
+	suite.fileHistory = NewFileHistory(suite.repo)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockFileHistory = mocks.NewMockFileHistory(suite.mockController)
+
+	suite.mapper = NewMapper(suite.mockRepo, suite.mockFileHistory)
+}
+
+func (suite *CommitLogMapperTestSuite) TestMap_ShouldMapCommitLogFieldsToModel() {
+	suite.mapper = NewMapper(suite.repo, suite.fileHistory)
+
+	got := suite.mapper.Map(suite.commits)
+
+	wantFileCount, _ := suite.fileHistory.Get(middleware.NewCommit(&suite.commits[0]))
+
+	suite.Len(got, 3)
+	suite.Equal(suite.commits[0].Id().String(), *got[0].Hash)
+	suite.Equal(suite.commits[0].Author().Name, *got[0].Author)
+	suite.Equal(suite.commits[0].Author().When.String(), *got[0].CommitTime)
+	suite.Equal(strings.Split(suite.commits[0].Message(), "\n")[0], *got[0].CommitMessage)
+	suite.Equal(len(wantFileCount), *got[0].CommitFilesCount)
+}
+
+func (suite *CommitLogMapperTestSuite) TestMap_WhenCommitListIsEmpty_ShouldReturnEmptyModelSlice() {
+	suite.mapper = NewMapper(suite.repo, suite.fileHistory)
+
+	got := suite.mapper.Map([]git2go.Commit{})
+
+	suite.Len(got, 0)
+}
+
+func (suite *CommitLogMapperTestSuite) TestMap_WhenCommitFileHistoryReturnsError_ShouldConsiderFileHistoryAsZero() {
+	suite.mapper = NewMapper(suite.repo, suite.mockFileHistory)
+
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&suite.commits[0])).Return(nil, errors.New("FILE_HISTORY_ERROR")).Times(3)
+
+	got := suite.mapper.Map(suite.commits)
+
+	suite.Len(got, 3)
+	suite.Equal(suite.commits[0].Id().String(), *got[0].Hash)
+	suite.Equal(suite.commits[0].Author().Name, *got[0].Author)
+	suite.Equal(suite.commits[0].Author().When.String(), *got[0].CommitTime)
+	suite.Equal(strings.Split(suite.commits[0].Message(), "\n")[0], *got[0].CommitMessage)
+	suite.Equal(0, *got[0].CommitFilesCount)
+}
diff --git a/mocks/mock_commit.go b/mocks/mock_commit.go
new file mode 100644
index 0000000..e6b0f84
--- /dev/null
+++ b/mocks/mock_commit.go
@@ -0,0 +1,93 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/commit.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+	middleware "github.com/neel1996/gitconvex/git/middleware"
+)
+
+// MockCommit is a mock of Commit interface.
+type MockCommit struct {
+	ctrl     *gomock.Controller
+	recorder *MockCommitMockRecorder
+}
+
+// MockCommitMockRecorder is the mock recorder for MockCommit.
+type MockCommitMockRecorder struct {
+	mock *MockCommit
+}
+
+// NewMockCommit creates a new mock instance.
+func NewMockCommit(ctrl *gomock.Controller) *MockCommit {
+	mock := &MockCommit{ctrl: ctrl}
+	mock.recorder = &MockCommitMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockCommit) EXPECT() *MockCommitMockRecorder {
+	return m.recorder
+}
+
+// Id mocks base method.
+func (m *MockCommit) Id() *git.Oid {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Id")
+	ret0, _ := ret[0].(*git.Oid)
+	return ret0
+}
+
+// Id indicates an expected call of Id.
+func (mr *MockCommitMockRecorder) Id() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockCommit)(nil).Id))
+}
+
+// Parent mocks base method.
+func (m *MockCommit) Parent(arg0 uint) middleware.Commit {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Parent", arg0)
+	ret0, _ := ret[0].(middleware.Commit)
+	return ret0
+}
+
+// Parent indicates an expected call of Parent.
+func (mr *MockCommitMockRecorder) Parent(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Parent", reflect.TypeOf((*MockCommit)(nil).Parent), arg0)
+}
+
+// ParentCount mocks base method.
+func (m *MockCommit) ParentCount() uint {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ParentCount")
+	ret0, _ := ret[0].(uint)
+	return ret0
+}
+
+// ParentCount indicates an expected call of ParentCount.
+func (mr *MockCommitMockRecorder) ParentCount() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParentCount", reflect.TypeOf((*MockCommit)(nil).ParentCount))
+}
+
+// Tree mocks base method.
+func (m *MockCommit) Tree() (*git.Tree, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Tree")
+	ret0, _ := ret[0].(*git.Tree)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Tree indicates an expected call of Tree.
+func (mr *MockCommitMockRecorder) Tree() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Tree", reflect.TypeOf((*MockCommit)(nil).Tree))
+}
diff --git a/mocks/mock_git_commit_file_history.go b/mocks/mock_git_commit_file_history.go
new file mode 100644
index 0000000..575db0a
--- /dev/null
+++ b/mocks/mock_git_commit_file_history.go
@@ -0,0 +1,51 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/commit/git_commit_file_history.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	middleware "github.com/neel1996/gitconvex/git/middleware"
+	model "github.com/neel1996/gitconvex/graph/model"
+)
+
+// MockFileHistory is a mock of FileHistory interface.
+type MockFileHistory struct {
+	ctrl     *gomock.Controller
+	recorder *MockFileHistoryMockRecorder
+}
+
+// MockFileHistoryMockRecorder is the mock recorder for MockFileHistory.
+type MockFileHistoryMockRecorder struct {
+	mock *MockFileHistory
+}
+
+// NewMockFileHistory creates a new mock instance.
+func NewMockFileHistory(ctrl *gomock.Controller) *MockFileHistory {
+	mock := &MockFileHistory{ctrl: ctrl}
+	mock.recorder = &MockFileHistoryMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockFileHistory) EXPECT() *MockFileHistoryMockRecorder {
+	return m.recorder
+}
+
+// Get mocks base method.
+func (m *MockFileHistory) Get(commit middleware.Commit) ([]*model.GitCommitFileResult, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Get", commit)
+	ret0, _ := ret[0].([]*model.GitCommitFileResult)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Get indicates an expected call of Get.
+func (mr *MockFileHistoryMockRecorder) Get(commit interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockFileHistory)(nil).Get), commit)
+}

From 9f93178adfcaa67c6a6631414d8b328adfc7525a Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 27 Jul 2021 22:10:53 +0530
Subject: [PATCH 064/148] remove old commit file history api

---
 git/git_commit_files.go | 80 -----------------------------------------
 1 file changed, 80 deletions(-)
 delete mode 100644 git/git_commit_files.go

diff --git a/git/git_commit_files.go b/git/git_commit_files.go
deleted file mode 100644
index b4dde1a..0000000
--- a/git/git_commit_files.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-)
-
-type CommitFileListInterface interface {
-	CommitFileList() []*model.GitCommitFileResult
-}
-
-type CommitFileListStruct struct {
-	Repo       *git2go.Repository
-	CommitHash string
-}
-
-// Common function for returning empty response in case of errors
-func returnCommitFileError(err error) []*model.GitCommitFileResult {
-	logger.Log(err.Error(), global.StatusError)
-	return []*model.GitCommitFileResult{{
-		Type:     "",
-		FileName: "",
-	}}
-}
-
-// CommitFileList returns the list of files modified, added or removed as part of a commit
-// compares the previous commit tree with the current commit tree and, returns the change type (M|D|A) and file name
-func (c CommitFileListStruct) CommitFileList() []*model.GitCommitFileResult {
-	var res []*model.GitCommitFileResult
-
-	repo := c.Repo
-	commitHash := c.CommitHash
-
-	logger.Log(fmt.Sprintf("Fetching file details for commit %v", commitHash), global.StatusInfo)
-
-	oid, oidErr := git2go.NewOid(commitHash)
-	if oidErr != nil {
-		return returnCommitFileError(oidErr)
-	}
-
-	commit, err := repo.LookupCommit(oid)
-	if err != nil {
-		return returnCommitFileError(err)
-	}
-
-	numParents := commit.ParentCount()
-	if numParents > 0 {
-		prevCommit := commit.Parent(0)
-		prevTree, _ := prevCommit.Tree()
-		commitTree, _ := commit.Tree()
-
-		if commitTree != nil && prevTree != nil {
-			diff, diffErr := repo.DiffTreeToTree(prevTree, commitTree, nil)
-			if diffErr != nil {
-				return returnCommitFileError(diffErr)
-			}
-
-			numDelta, numDeltaErr := diff.NumDeltas()
-			if numDeltaErr != nil {
-				return returnCommitFileError(numDeltaErr)
-			}
-			for d := 0; d < numDelta; d++ {
-				delta, _ := diff.Delta(d)
-				status := delta.Status.String()
-				res = append(res, &model.GitCommitFileResult{
-					Type:     status[0:1],
-					FileName: delta.NewFile.Path,
-				})
-			}
-		}
-	} else {
-		return []*model.GitCommitFileResult{{
-			Type:     "",
-			FileName: "",
-		}}
-	}
-	return res
-}

From 818f505dd413e8f7db8ca7382d691d9f404829e9 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 27 Jul 2021 22:26:40 +0530
Subject: [PATCH 065/148] update commit error models

---
 git/commit/commit.go                       | 20 +++++++++++++++++---
 git/commit/errors.go                       | 10 +++++-----
 git/commit/git_commit_file_history.go      |  6 +++---
 git/commit/git_commit_file_history_test.go |  8 ++++----
 4 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/git/commit/commit.go b/git/commit/commit.go
index 73726c8..8ab7e3f 100644
--- a/git/commit/commit.go
+++ b/git/commit/commit.go
@@ -2,6 +2,7 @@ package commit
 
 import (
 	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
 )
 
 var logger global.Logger
@@ -11,8 +12,11 @@ type Commit interface {
 }
 
 type Operation struct {
-	Changes Changes
-	Total   Total
+	Changes     Changes
+	Total       Total
+	ListAllLogs ListAllLogs
+	FileHistory FileHistory
+	Mapper      Mapper
 }
 
 func (c Operation) GitCommitChange() (string, error) {
@@ -20,7 +24,7 @@ func (c Operation) GitCommitChange() (string, error) {
 
 	if err != nil {
 		logger.Log(err.Error(), global.StatusError)
-		return "", CommitLogsError
+		return "", ChangeError
 	}
 
 	return global.CommitChangeSuccess, nil
@@ -29,3 +33,13 @@ func (c Operation) GitCommitChange() (string, error) {
 func (c Operation) GitTotalCommits() int {
 	return c.Total.Get()
 }
+
+func (c Operation) GitCommitLogs() ([]*model.GitCommits, error) {
+	commits, logsErr := c.ListAllLogs.Get()
+	if logsErr != nil {
+		logger.Log(logsErr.Error(), global.StatusError)
+		return nil, LogsError
+	}
+
+	return c.Mapper.Map(commits), nil
+}
diff --git a/git/commit/errors.go b/git/commit/errors.go
index c85e003..8cf7612 100644
--- a/git/commit/errors.go
+++ b/git/commit/errors.go
@@ -7,11 +7,11 @@ type Error struct {
 }
 
 var (
-	CommitChangeError              = Error{ErrorCode: "COMMIT_FAILED", ErrorString: "Failed to delete add new remote"}
-	CommitLogsError                = Error{ErrorCode: "LIST_COMMIT_LOGS_FAILED", ErrorString: "Failed to delete add new remote"}
-	CommitFileHistoryError         = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_FAILED", ErrorString: "Failed to get the list of file changes for the commit"}
-	CommitFileHistoryNoParentError = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_NO_PARENT", ErrorString: "The HEAD commit is the only commit in the repo and has no previous histories"}
-	CommitFileHistoryTreeError     = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_INVALID_TREE", ErrorString: "The commit tree is invalid"}
+	ChangeError              = Error{ErrorCode: "COMMIT_FAILED", ErrorString: "Failed to commit the new changes"}
+	LogsError                = Error{ErrorCode: "LIST_COMMIT_LOGS_FAILED", ErrorString: "Failed to list the commit logs for the repo"}
+	FileHistoryError         = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_FAILED", ErrorString: "Failed to get the list of file changes for the commit"}
+	FileHistoryNoParentError = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_NO_PARENT", ErrorString: "The HEAD commit is the only commit in the repo and has no previous histories"}
+	FileHistoryTreeError     = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_INVALID_TREE", ErrorString: "The commit tree is invalid"}
 )
 
 func (e Error) Error() string {
diff --git a/git/commit/git_commit_file_history.go b/git/commit/git_commit_file_history.go
index 1316f5f..5b6ba25 100644
--- a/git/commit/git_commit_file_history.go
+++ b/git/commit/git_commit_file_history.go
@@ -36,7 +36,7 @@ func (f fileHistory) treesOf(commit middleware.Commit) (*git2go.Tree, *git2go.Tr
 	parents := commit.ParentCount()
 	if parents == 0 {
 		logger.Log("Commit has no parent", global.StatusError)
-		return nil, nil, CommitFileHistoryNoParentError
+		return nil, nil, FileHistoryNoParentError
 	}
 
 	previousCommit := commit.Parent(0)
@@ -45,7 +45,7 @@ func (f fileHistory) treesOf(commit middleware.Commit) (*git2go.Tree, *git2go.Tr
 	currentTree, treeErr := commit.Tree()
 	if treeErr != nil {
 		logger.Log(treeErr.Error(), global.StatusError)
-		return nil, nil, CommitFileHistoryTreeError
+		return nil, nil, FileHistoryTreeError
 	}
 
 	return previousTree, currentTree, nil
@@ -80,7 +80,7 @@ func (f fileHistory) diffBetweenTrees(previousTree *git2go.Tree, currentTree *gi
 func fileHistoryError(err error) ([]*model.GitCommitFileResult, error) {
 	logger.Log(err.Error(), global.StatusError)
 	if reflect.TypeOf(err) != reflect.TypeOf(Error{}) {
-		return nil, CommitFileHistoryError
+		return nil, FileHistoryError
 	}
 	return nil, err
 }
diff --git a/git/commit/git_commit_file_history_test.go b/git/commit/git_commit_file_history_test.go
index 59dbd48..41d48b2 100644
--- a/git/commit/git_commit_file_history_test.go
+++ b/git/commit/git_commit_file_history_test.go
@@ -59,7 +59,7 @@ func (suite *FileHistoryTestSuite) TestGet_WhenCommitIsTheFirstCommitWithNoParen
 	_, err := suite.fileHistory.Get(suite.mockCommit)
 
 	suite.NotNil(err)
-	suite.Equal(CommitFileHistoryNoParentError, err)
+	suite.Equal(FileHistoryNoParentError, err)
 }
 
 func (suite *FileHistoryTestSuite) TestGet_WhenCommitTreeIsInvalid_ShouldReturnTreeError() {
@@ -73,7 +73,7 @@ func (suite *FileHistoryTestSuite) TestGet_WhenCommitTreeIsInvalid_ShouldReturnT
 	_, err := suite.fileHistory.Get(suite.mockCommit)
 
 	suite.NotNil(err)
-	suite.Equal(CommitFileHistoryTreeError, err)
+	suite.Equal(FileHistoryTreeError, err)
 }
 
 func (suite *FileHistoryTestSuite) TestGet_WhenDiffTreeFails_ShouldReturnError() {
@@ -90,7 +90,7 @@ func (suite *FileHistoryTestSuite) TestGet_WhenDiffTreeFails_ShouldReturnError()
 	_, err := suite.fileHistory.Get(suite.mockCommit)
 
 	suite.NotNil(err)
-	suite.Equal(CommitFileHistoryError, err)
+	suite.Equal(FileHistoryError, err)
 }
 
 func (suite *FileHistoryTestSuite) TestGet_WhenDiffNumDeltaIsZero_ShouldReturnError() {
@@ -107,5 +107,5 @@ func (suite *FileHistoryTestSuite) TestGet_WhenDiffNumDeltaIsZero_ShouldReturnEr
 	_, err := suite.fileHistory.Get(suite.mockCommit)
 
 	suite.NotNil(err)
-	suite.Equal(CommitFileHistoryError, err)
+	suite.Equal(FileHistoryError, err)
 }

From 84249953e202ce6ec323691e9f8fbd3870061f79 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 28 Jul 2021 22:34:59 +0530
Subject: [PATCH 066/148] create new search factory for commit log search api

---
 constants/global_constants.go              |  5 +++
 git/commit/search/commit_author_search.go  | 44 ++++++++++++++++++++
 git/commit/search/commit_hash_search.go    | 44 ++++++++++++++++++++
 git/commit/search/commit_message_search.go | 44 ++++++++++++++++++++
 git/commit/search/search.go                | 12 ++++++
 git/commit/search/search_factory.go        | 47 ++++++++++++++++++++++
 6 files changed, 196 insertions(+)
 create mode 100644 constants/global_constants.go
 create mode 100644 git/commit/search/commit_author_search.go
 create mode 100644 git/commit/search/commit_hash_search.go
 create mode 100644 git/commit/search/commit_message_search.go
 create mode 100644 git/commit/search/search.go
 create mode 100644 git/commit/search/search_factory.go

diff --git a/constants/global_constants.go b/constants/global_constants.go
new file mode 100644
index 0000000..f304634
--- /dev/null
+++ b/constants/global_constants.go
@@ -0,0 +1,5 @@
+package constants
+
+const (
+	SearchLimit = 10
+)
diff --git a/git/commit/search/commit_author_search.go b/git/commit/search/commit_author_search.go
new file mode 100644
index 0000000..47ebfa0
--- /dev/null
+++ b/git/commit/search/commit_author_search.go
@@ -0,0 +1,44 @@
+package search
+
+import (
+	git "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/constants"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/graph/model"
+	"regexp"
+)
+
+type commitAuthorSearch struct {
+	commits []git.Commit
+	mapper  commit.Mapper
+}
+
+func (h commitAuthorSearch) New(commits []git.Commit, mapper commit.Mapper) Search {
+	return commitAuthorSearch{commits: commits, mapper: mapper}
+}
+
+func (h commitAuthorSearch) Search(searchKey string) []*model.GitCommits {
+	var (
+		matchingCommits []*model.GitCommits
+		counter         = 0
+	)
+
+	for _, c := range h.commits {
+		if h.isExceedingSearchLimit(counter) {
+			break
+		}
+
+		if isMatch, _ := regexp.MatchString(searchKey, c.Author().Name); isMatch {
+			commitLog := h.mapper.Map([]git.Commit{c})
+			matchingCommits = append(matchingCommits, commitLog...)
+		}
+
+		counter++
+	}
+
+	return matchingCommits
+}
+
+func (h commitAuthorSearch) isExceedingSearchLimit(searchLimitCounter int) bool {
+	return searchLimitCounter == constants.SearchLimit
+}
diff --git a/git/commit/search/commit_hash_search.go b/git/commit/search/commit_hash_search.go
new file mode 100644
index 0000000..bf5c08f
--- /dev/null
+++ b/git/commit/search/commit_hash_search.go
@@ -0,0 +1,44 @@
+package search
+
+import (
+	git "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/constants"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/graph/model"
+	"regexp"
+)
+
+type commitHashSearch struct {
+	commits []git.Commit
+	mapper  commit.Mapper
+}
+
+func (h commitHashSearch) New(commits []git.Commit, mapper commit.Mapper) Search {
+	return commitHashSearch{commits: commits, mapper: mapper}
+}
+
+func (h commitHashSearch) Search(searchKey string) []*model.GitCommits {
+	var (
+		matchingCommits []*model.GitCommits
+		counter         = 0
+	)
+
+	for _, c := range h.commits {
+		if h.isExceedingSearchLimit(counter) {
+			break
+		}
+
+		if isMatch, _ := regexp.MatchString(searchKey, c.Id().String()); isMatch {
+			commitLog := h.mapper.Map([]git.Commit{c})
+			matchingCommits = append(matchingCommits, commitLog...)
+		}
+
+		counter++
+	}
+
+	return matchingCommits
+}
+
+func (h commitHashSearch) isExceedingSearchLimit(searchLimitCounter int) bool {
+	return searchLimitCounter == constants.SearchLimit
+}
diff --git a/git/commit/search/commit_message_search.go b/git/commit/search/commit_message_search.go
new file mode 100644
index 0000000..04d3e6e
--- /dev/null
+++ b/git/commit/search/commit_message_search.go
@@ -0,0 +1,44 @@
+package search
+
+import (
+	git "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/constants"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/graph/model"
+	"regexp"
+)
+
+type commitMessageSearch struct {
+	commits []git.Commit
+	mapper  commit.Mapper
+}
+
+func (m commitMessageSearch) New(commits []git.Commit, mapper commit.Mapper) Search {
+	return commitMessageSearch{commits: commits, mapper: mapper}
+}
+
+func (m commitMessageSearch) Search(searchKey string) []*model.GitCommits {
+	var (
+		matchingCommits []*model.GitCommits
+		counter         = 0
+	)
+
+	for _, c := range m.commits {
+		if m.isExceedingSearchLimit(counter) {
+			break
+		}
+
+		if isMatch, _ := regexp.MatchString(searchKey, c.Message()); isMatch {
+			commitLog := m.mapper.Map([]git.Commit{c})
+			matchingCommits = append(matchingCommits, commitLog...)
+		}
+
+		counter++
+	}
+
+	return matchingCommits
+}
+
+func (m commitMessageSearch) isExceedingSearchLimit(searchLimitCounter int) bool {
+	return searchLimitCounter == constants.SearchLimit
+}
diff --git a/git/commit/search/search.go b/git/commit/search/search.go
new file mode 100644
index 0000000..5aecab4
--- /dev/null
+++ b/git/commit/search/search.go
@@ -0,0 +1,12 @@
+package search
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type Search interface {
+	Search(string) []*model.GitCommits
+	New([]git2go.Commit, commit.Mapper) Search
+}
diff --git a/git/commit/search/search_factory.go b/git/commit/search/search_factory.go
new file mode 100644
index 0000000..26615d3
--- /dev/null
+++ b/git/commit/search/search_factory.go
@@ -0,0 +1,47 @@
+package search
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+type Type int
+
+const (
+	CommitHash = iota
+	CommitMessage
+	CommitAuthor
+)
+
+var typeMap = map[string]Type{
+	"hash":    CommitHash,
+	"message": CommitMessage,
+	"author":  CommitAuthor,
+}
+
+func GetSearchAction(repo middleware.Repository, searchType string, commits []git2go.Commit) Search {
+	mappedSearchType := typeMap[searchType]
+
+	mapper := commit.NewMapper(repo, commit.NewFileHistory(repo))
+
+	switch mappedSearchType {
+	case CommitHash:
+		return commitHashSearch{
+			commits: commits,
+			mapper:  mapper,
+		}
+	case CommitMessage:
+		return commitMessageSearch{
+			commits: commits,
+			mapper:  mapper,
+		}
+	case CommitAuthor:
+		return commitAuthorSearch{
+			commits: commits,
+			mapper:  mapper,
+		}
+	}
+
+	return nil
+}

From 44f14ae8839ff01ca47019d6ecd50b9de1bac730 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 28 Jul 2021 22:45:30 +0530
Subject: [PATCH 067/148] remove unused repo field from mapper struct

---
 git/commit/git_commit_log_mapper.go      | 4 +---
 git/commit/git_commit_log_mapper_test.go | 8 ++++----
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/git/commit/git_commit_log_mapper.go b/git/commit/git_commit_log_mapper.go
index e64ae70..5d38dd9 100644
--- a/git/commit/git_commit_log_mapper.go
+++ b/git/commit/git_commit_log_mapper.go
@@ -13,7 +13,6 @@ type Mapper interface {
 }
 
 type mapper struct {
-	repo        middleware.Repository
 	fileHistory FileHistory
 }
 
@@ -71,9 +70,8 @@ func (m mapper) commitFileHistory(commit git2go.Commit) int {
 	return len(fileHistory)
 }
 
-func NewMapper(repo middleware.Repository, commitFile FileHistory) Mapper {
+func NewMapper(commitFile FileHistory) Mapper {
 	return mapper{
-		repo:        repo,
 		fileHistory: commitFile,
 	}
 }
diff --git a/git/commit/git_commit_log_mapper_test.go b/git/commit/git_commit_log_mapper_test.go
index 612f626..86ad41d 100644
--- a/git/commit/git_commit_log_mapper_test.go
+++ b/git/commit/git_commit_log_mapper_test.go
@@ -44,11 +44,11 @@ func (suite *CommitLogMapperTestSuite) SetupTest() {
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
 	suite.mockFileHistory = mocks.NewMockFileHistory(suite.mockController)
 
-	suite.mapper = NewMapper(suite.mockRepo, suite.mockFileHistory)
+	suite.mapper = NewMapper(suite.mockFileHistory)
 }
 
 func (suite *CommitLogMapperTestSuite) TestMap_ShouldMapCommitLogFieldsToModel() {
-	suite.mapper = NewMapper(suite.repo, suite.fileHistory)
+	suite.mapper = NewMapper(suite.fileHistory)
 
 	got := suite.mapper.Map(suite.commits)
 
@@ -63,7 +63,7 @@ func (suite *CommitLogMapperTestSuite) TestMap_ShouldMapCommitLogFieldsToModel()
 }
 
 func (suite *CommitLogMapperTestSuite) TestMap_WhenCommitListIsEmpty_ShouldReturnEmptyModelSlice() {
-	suite.mapper = NewMapper(suite.repo, suite.fileHistory)
+	suite.mapper = NewMapper(suite.fileHistory)
 
 	got := suite.mapper.Map([]git2go.Commit{})
 
@@ -71,7 +71,7 @@ func (suite *CommitLogMapperTestSuite) TestMap_WhenCommitListIsEmpty_ShouldRetur
 }
 
 func (suite *CommitLogMapperTestSuite) TestMap_WhenCommitFileHistoryReturnsError_ShouldConsiderFileHistoryAsZero() {
-	suite.mapper = NewMapper(suite.repo, suite.mockFileHistory)
+	suite.mapper = NewMapper(suite.mockFileHistory)
 
 	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&suite.commits[0])).Return(nil, errors.New("FILE_HISTORY_ERROR")).Times(3)
 

From 1101045d9eed79132bdeb3b95ae1be4669fccfc3 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 28 Jul 2021 23:25:39 +0530
Subject: [PATCH 068/148] resolve cyclic dependency error by removing mapper
 out of search factory

---
 git/commit/search/commit_author_search.go  | 18 +++++++-----------
 git/commit/search/commit_hash_search.go    | 18 +++++++-----------
 git/commit/search/commit_message_search.go | 18 +++++++-----------
 git/commit/search/search.go                |  6 ++----
 git/commit/search/search_factory.go        |  9 +--------
 5 files changed, 24 insertions(+), 45 deletions(-)

diff --git a/git/commit/search/commit_author_search.go b/git/commit/search/commit_author_search.go
index 47ebfa0..3913327 100644
--- a/git/commit/search/commit_author_search.go
+++ b/git/commit/search/commit_author_search.go
@@ -3,34 +3,30 @@ package search
 import (
 	git "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/constants"
-	"github.com/neel1996/gitconvex/git/commit"
-	"github.com/neel1996/gitconvex/graph/model"
 	"regexp"
 )
 
 type commitAuthorSearch struct {
 	commits []git.Commit
-	mapper  commit.Mapper
 }
 
-func (h commitAuthorSearch) New(commits []git.Commit, mapper commit.Mapper) Search {
-	return commitAuthorSearch{commits: commits, mapper: mapper}
+func (h commitAuthorSearch) New(commits []git.Commit) Search {
+	return commitAuthorSearch{commits: commits}
 }
 
-func (h commitAuthorSearch) Search(searchKey string) []*model.GitCommits {
+func (h commitAuthorSearch) Search(searchKey string) []git.Commit {
 	var (
-		matchingCommits []*model.GitCommits
+		matchingCommits []git.Commit
 		counter         = 0
 	)
 
-	for _, c := range h.commits {
+	for _, commit := range h.commits {
 		if h.isExceedingSearchLimit(counter) {
 			break
 		}
 
-		if isMatch, _ := regexp.MatchString(searchKey, c.Author().Name); isMatch {
-			commitLog := h.mapper.Map([]git.Commit{c})
-			matchingCommits = append(matchingCommits, commitLog...)
+		if isMatch, _ := regexp.MatchString(searchKey, commit.Author().Name); isMatch {
+			matchingCommits = append(matchingCommits, commit)
 		}
 
 		counter++
diff --git a/git/commit/search/commit_hash_search.go b/git/commit/search/commit_hash_search.go
index bf5c08f..374d753 100644
--- a/git/commit/search/commit_hash_search.go
+++ b/git/commit/search/commit_hash_search.go
@@ -3,34 +3,30 @@ package search
 import (
 	git "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/constants"
-	"github.com/neel1996/gitconvex/git/commit"
-	"github.com/neel1996/gitconvex/graph/model"
 	"regexp"
 )
 
 type commitHashSearch struct {
 	commits []git.Commit
-	mapper  commit.Mapper
 }
 
-func (h commitHashSearch) New(commits []git.Commit, mapper commit.Mapper) Search {
-	return commitHashSearch{commits: commits, mapper: mapper}
+func (h commitHashSearch) New(commits []git.Commit) Search {
+	return commitHashSearch{commits: commits}
 }
 
-func (h commitHashSearch) Search(searchKey string) []*model.GitCommits {
+func (h commitHashSearch) Search(searchKey string) []git.Commit {
 	var (
-		matchingCommits []*model.GitCommits
+		matchingCommits []git.Commit
 		counter         = 0
 	)
 
-	for _, c := range h.commits {
+	for _, commit := range h.commits {
 		if h.isExceedingSearchLimit(counter) {
 			break
 		}
 
-		if isMatch, _ := regexp.MatchString(searchKey, c.Id().String()); isMatch {
-			commitLog := h.mapper.Map([]git.Commit{c})
-			matchingCommits = append(matchingCommits, commitLog...)
+		if isMatch, _ := regexp.MatchString(searchKey, commit.Id().String()); isMatch {
+			matchingCommits = append(matchingCommits, commit)
 		}
 
 		counter++
diff --git a/git/commit/search/commit_message_search.go b/git/commit/search/commit_message_search.go
index 04d3e6e..a9f3a71 100644
--- a/git/commit/search/commit_message_search.go
+++ b/git/commit/search/commit_message_search.go
@@ -3,34 +3,30 @@ package search
 import (
 	git "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/constants"
-	"github.com/neel1996/gitconvex/git/commit"
-	"github.com/neel1996/gitconvex/graph/model"
 	"regexp"
 )
 
 type commitMessageSearch struct {
 	commits []git.Commit
-	mapper  commit.Mapper
 }
 
-func (m commitMessageSearch) New(commits []git.Commit, mapper commit.Mapper) Search {
-	return commitMessageSearch{commits: commits, mapper: mapper}
+func (m commitMessageSearch) New(commits []git.Commit) Search {
+	return commitMessageSearch{commits: commits}
 }
 
-func (m commitMessageSearch) Search(searchKey string) []*model.GitCommits {
+func (m commitMessageSearch) Search(searchKey string) []git.Commit {
 	var (
-		matchingCommits []*model.GitCommits
+		matchingCommits []git.Commit
 		counter         = 0
 	)
 
-	for _, c := range m.commits {
+	for _, commit := range m.commits {
 		if m.isExceedingSearchLimit(counter) {
 			break
 		}
 
-		if isMatch, _ := regexp.MatchString(searchKey, c.Message()); isMatch {
-			commitLog := m.mapper.Map([]git.Commit{c})
-			matchingCommits = append(matchingCommits, commitLog...)
+		if isMatch, _ := regexp.MatchString(searchKey, commit.Message()); isMatch {
+			matchingCommits = append(matchingCommits, commit)
 		}
 
 		counter++
diff --git a/git/commit/search/search.go b/git/commit/search/search.go
index 5aecab4..bcf3132 100644
--- a/git/commit/search/search.go
+++ b/git/commit/search/search.go
@@ -2,11 +2,9 @@ package search
 
 import (
 	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/git/commit"
-	"github.com/neel1996/gitconvex/graph/model"
 )
 
 type Search interface {
-	Search(string) []*model.GitCommits
-	New([]git2go.Commit, commit.Mapper) Search
+	Search(string) []git2go.Commit
+	New([]git2go.Commit) Search
 }
diff --git a/git/commit/search/search_factory.go b/git/commit/search/search_factory.go
index 26615d3..32ea6b5 100644
--- a/git/commit/search/search_factory.go
+++ b/git/commit/search/search_factory.go
@@ -2,8 +2,6 @@ package search
 
 import (
 	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/git/commit"
-	"github.com/neel1996/gitconvex/git/middleware"
 )
 
 type Type int
@@ -20,26 +18,21 @@ var typeMap = map[string]Type{
 	"author":  CommitAuthor,
 }
 
-func GetSearchAction(repo middleware.Repository, searchType string, commits []git2go.Commit) Search {
+func GetSearchAction(searchType string, commits []git2go.Commit) Search {
 	mappedSearchType := typeMap[searchType]
 
-	mapper := commit.NewMapper(repo, commit.NewFileHistory(repo))
-
 	switch mappedSearchType {
 	case CommitHash:
 		return commitHashSearch{
 			commits: commits,
-			mapper:  mapper,
 		}
 	case CommitMessage:
 		return commitMessageSearch{
 			commits: commits,
-			mapper:  mapper,
 		}
 	case CommitAuthor:
 		return commitAuthorSearch{
 			commits: commits,
-			mapper:  mapper,
 		}
 	}
 

From 8f6d5cdc18e78eeae0dfc24ad3a5730cf5404ad1 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 28 Jul 2021 23:38:09 +0530
Subject: [PATCH 069/148] add default branch for invalid search type

---
 git/commit/search/search_factory.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/git/commit/search/search_factory.go b/git/commit/search/search_factory.go
index 32ea6b5..be6a261 100644
--- a/git/commit/search/search_factory.go
+++ b/git/commit/search/search_factory.go
@@ -7,7 +7,7 @@ import (
 type Type int
 
 const (
-	CommitHash = iota
+	CommitHash = iota + 1
 	CommitMessage
 	CommitAuthor
 )
@@ -34,7 +34,7 @@ func GetSearchAction(searchType string, commits []git2go.Commit) Search {
 		return commitAuthorSearch{
 			commits: commits,
 		}
+	default:
+		return nil
 	}
-
-	return nil
 }

From 8dda302b7775e599ce3e96363fe60c3fd9d9e653 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 28 Jul 2021 23:50:45 +0530
Subject: [PATCH 070/148] add new api for commit log search

---
 constants/errors.go                      |  35 ++---
 git/commit/errors.go                     |   1 +
 git/commit/git_commit_log_search.go      |  48 ++++++
 git/commit/git_commit_log_search_test.go | 182 +++++++++++++++++++++++
 git/git_commit_log_search.go             |  69 ---------
 5 files changed, 247 insertions(+), 88 deletions(-)
 create mode 100644 git/commit/git_commit_log_search.go
 create mode 100644 git/commit/git_commit_log_search_test.go
 delete mode 100644 git/git_commit_log_search.go

diff --git a/constants/errors.go b/constants/errors.go
index abf4706..26ba1ed 100644
--- a/constants/errors.go
+++ b/constants/errors.go
@@ -7,25 +7,22 @@ type ApiError struct {
 }
 
 var (
-	BranchAddError         = ApiError{ErrorCode: "BRANCH_ADD_FAILED", ErrorString: "Failed to add new branch"}
-	BranchCheckoutError    = ApiError{ErrorCode: "CHECKOUT_FAILED", ErrorString: "Failed to checkout branch"}
-	BranchDeleteError      = ApiError{ErrorCode: "BRANCH_DELETE_FAILED", ErrorString: "Failed to delete branch"}
-	RemoteAddError         = ApiError{ErrorCode: "REMOTE_ADD_FAILED", ErrorString: "Failed to delete add new remote"}
-	RemoteDeleteError      = ApiError{ErrorCode: "REMOTE_DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
-	RemoteEditError        = ApiError{ErrorCode: "REMOTE_EDIT_FAILED", ErrorString: "Failed to delete add new remote"}
-	FetchFromRemoteError   = ApiError{ErrorCode: "FETCH_ERROR", ErrorString: "Failed to delete add new remote"}
-	PullFromRemoteError    = ApiError{ErrorCode: "PULL_ERROR", ErrorString: "Failed to delete add new remote"}
-	StageItemError         = ApiError{ErrorCode: "ADD_ITEM_FAILED", ErrorString: "Failed to delete add new remote"}
-	StageAllItemsError     = ApiError{ErrorCode: "ALL_STAGE_FAILED", ErrorString: "Failed to delete add new remote"}
-	RemoveItemError        = ApiError{ErrorCode: "STAGE_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
-	RemoveAllItemsError    = ApiError{ErrorCode: "STAGE_ALL_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
-	CommitChangeError      = ApiError{ErrorCode: "COMMIT_FAILED", ErrorString: "Failed to delete add new remote"}
-	PushToRemoteError      = ApiError{ErrorCode: "PUSH_FAILED", ErrorString: "Failed to delete add new remote"}
-	PortUpdateError        = ApiError{ErrorCode: "PORT_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
-	DataFileUpdateError    = ApiError{ErrorCode: "DATAFILE_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
-	RepoDeleteError        = ApiError{ErrorCode: "DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
-	CommitLogsError        = ApiError{ErrorCode: "LIST_COMMIT_LOGS_FAILED", ErrorString: "Failed to delete add new remote"}
-	CommitFileHistoryError = ApiError{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_FAILED", ErrorString: "Failed to get the list of file changes for the commit"}
+	BranchAddError       = ApiError{ErrorCode: "BRANCH_ADD_FAILED", ErrorString: "Failed to add new branch"}
+	BranchCheckoutError  = ApiError{ErrorCode: "CHECKOUT_FAILED", ErrorString: "Failed to checkout branch"}
+	BranchDeleteError    = ApiError{ErrorCode: "BRANCH_DELETE_FAILED", ErrorString: "Failed to delete branch"}
+	RemoteAddError       = ApiError{ErrorCode: "REMOTE_ADD_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoteDeleteError    = ApiError{ErrorCode: "REMOTE_DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoteEditError      = ApiError{ErrorCode: "REMOTE_EDIT_FAILED", ErrorString: "Failed to delete add new remote"}
+	FetchFromRemoteError = ApiError{ErrorCode: "FETCH_ERROR", ErrorString: "Failed to delete add new remote"}
+	PullFromRemoteError  = ApiError{ErrorCode: "PULL_ERROR", ErrorString: "Failed to delete add new remote"}
+	StageItemError       = ApiError{ErrorCode: "ADD_ITEM_FAILED", ErrorString: "Failed to delete add new remote"}
+	StageAllItemsError   = ApiError{ErrorCode: "ALL_STAGE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoveItemError      = ApiError{ErrorCode: "STAGE_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoveAllItemsError  = ApiError{ErrorCode: "STAGE_ALL_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
+	PushToRemoteError    = ApiError{ErrorCode: "PUSH_FAILED", ErrorString: "Failed to delete add new remote"}
+	PortUpdateError      = ApiError{ErrorCode: "PORT_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
+	DataFileUpdateError  = ApiError{ErrorCode: "DATAFILE_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RepoDeleteError      = ApiError{ErrorCode: "DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
 )
 
 func (e ApiError) Error() string {
diff --git a/git/commit/errors.go b/git/commit/errors.go
index 8cf7612..4f2b4a9 100644
--- a/git/commit/errors.go
+++ b/git/commit/errors.go
@@ -12,6 +12,7 @@ var (
 	FileHistoryError         = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_FAILED", ErrorString: "Failed to get the list of file changes for the commit"}
 	FileHistoryNoParentError = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_NO_PARENT", ErrorString: "The HEAD commit is the only commit in the repo and has no previous histories"}
 	FileHistoryTreeError     = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_INVALID_TREE", ErrorString: "The commit tree is invalid"}
+	InvalidSearchCategory    = Error{ErrorCode: "COMMIT_SEARCH_INVALID_SEARCH_TYPE", ErrorString: "The selected search category is invalid"}
 )
 
 func (e Error) Error() string {
diff --git a/git/commit/git_commit_log_search.go b/git/commit/git_commit_log_search.go
new file mode 100644
index 0000000..0c48b55
--- /dev/null
+++ b/git/commit/git_commit_log_search.go
@@ -0,0 +1,48 @@
+package commit
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git/commit/search"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type SearchLogs interface {
+	GetMatchingLogs(searchType string, searchKey string) ([]*model.GitCommits, error)
+}
+
+type searchLogs struct {
+	repo           middleware.Repository
+	listCommitLogs ListAllLogs
+	mapper         Mapper
+}
+
+// GetMatchingLogs searches for the required commits matching the searchKey with the respective searchType
+//
+// The UI uses 'message' as the default search type to look up based on commit messages
+func (s searchLogs) GetMatchingLogs(searchType string, searchKey string) ([]*model.GitCommits, error) {
+	logger.Log(fmt.Sprintf("Searching commit logs filtered with - %s for -> %s", searchType, searchKey), global.StatusInfo)
+
+	commits, listErr := s.listCommitLogs.Get()
+	if listErr != nil {
+		logger.Log("Unable to fetch commit logs : "+listErr.Error(), global.StatusError)
+		return nil, listErr
+	}
+
+	searchFactory := search.GetSearchAction(searchType, commits)
+	if searchFactory == nil {
+		logger.Log("Invalid search category", global.StatusError)
+		return nil, InvalidSearchCategory
+	}
+
+	return s.mapper.Map(searchFactory.Search(searchKey)), nil
+}
+
+func NewSearchLogs(repo middleware.Repository, listCommitLogs ListAllLogs, mapper Mapper) SearchLogs {
+	return searchLogs{
+		repo:           repo,
+		listCommitLogs: listCommitLogs,
+		mapper:         mapper,
+	}
+}
diff --git a/git/commit/git_commit_log_search_test.go b/git/commit/git_commit_log_search_test.go
new file mode 100644
index 0000000..be6ce25
--- /dev/null
+++ b/git/commit/git_commit_log_search_test.go
@@ -0,0 +1,182 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/constants"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/graph/model"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"strings"
+	"testing"
+)
+
+type SearchLogsTestSuite struct {
+	suite.Suite
+	mockController  *gomock.Controller
+	mockRepo        *mocks.MockRepository
+	mockListLogs    *mocks.MockListAllLogs
+	mockFileHistory *mocks.MockFileHistory
+	listAllLogs     ListAllLogs
+	mapper          Mapper
+	searchLogs      SearchLogs
+}
+
+func TestSearchLogsTestSuite(t *testing.T) {
+	suite.Run(t, new(SearchLogsTestSuite))
+}
+
+func (suite *SearchLogsTestSuite) SetupSuite() {
+	r, err := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.listAllLogs = NewListAllLogs(middleware.NewRepository(r), nil, nil)
+}
+
+func (suite *SearchLogsTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockListLogs = mocks.NewMockListAllLogs(suite.mockController)
+	suite.mockFileHistory = mocks.NewMockFileHistory(suite.mockController)
+
+	suite.mapper = NewMapper(suite.mockFileHistory)
+	suite.searchLogs = NewSearchLogs(suite.mockRepo, suite.mockListLogs, suite.mapper)
+}
+
+func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsHash_ShouldReturnMatchingCommits() {
+	commits := suite.commitLogs()
+	wantCommit := commits[0]
+	searchKey := wantCommit.Id().String()[0:8]
+
+	want := bindWithModel([]git.Commit{wantCommit})
+
+	suite.mockListLogs.EXPECT().Get().Return(commits, nil)
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return([]*model.GitCommitFileResult{{}}, nil)
+
+	got, err := suite.searchLogs.GetMatchingLogs("hash", searchKey)
+
+	suite.Nil(err)
+	suite.Equal(*want[0].Hash, *got[0].Hash)
+}
+
+func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsMessage_ShouldReturnMatchingCommits() {
+	commits := suite.commitLogs()
+	wantCommit := commits[0]
+	searchKey := strings.Split(wantCommit.Message(), " ")[0]
+
+	want := bindWithModel([]git.Commit{wantCommit})
+
+	suite.mockListLogs.EXPECT().Get().Return(commits, nil)
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return([]*model.GitCommitFileResult{{}}, nil)
+
+	got, err := suite.searchLogs.GetMatchingLogs("message", searchKey)
+
+	suite.Nil(err)
+	suite.Equal(*want[0].CommitMessage, *got[0].CommitMessage)
+}
+
+func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsAuthor_ShouldReturnMatchingCommits() {
+	commits := suite.commitLogs()
+	wantCommit := commits[0]
+	searchKey := wantCommit.Author().Name[0:3]
+
+	want := bindWithModel([]git.Commit{wantCommit})
+
+	suite.mockListLogs.EXPECT().Get().Return(commits, nil)
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return([]*model.GitCommitFileResult{{}}, nil)
+
+	got, err := suite.searchLogs.GetMatchingLogs("author", searchKey)
+
+	suite.Nil(err)
+	suite.Equal(*want[0].Author, *got[0].Author)
+}
+
+func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsInvalid_ShouldReturnError() {
+	commits := suite.commitLogs()
+	wantCommit := commits[0]
+	searchKey := wantCommit.Author().Name[0:3]
+
+	suite.mockListLogs.EXPECT().Get().Return(commits, nil)
+
+	_, err := suite.searchLogs.GetMatchingLogs("invalid", searchKey)
+
+	suite.NotNil(err)
+	suite.Equal(InvalidSearchCategory, err)
+}
+
+func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenListLogsReturnsError_ShouldReturnError() {
+	commits := suite.commitLogs()
+	wantCommit := commits[0]
+	searchKey := wantCommit.Author().Name[0:3]
+
+	suite.mockListLogs.EXPECT().Get().Return(nil, errors.New("LIST_LOGS_ERROR"))
+
+	_, err := suite.searchLogs.GetMatchingLogs("hash", searchKey)
+
+	suite.NotNil(err)
+}
+
+func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenCommitLogsExceedsSearchLimit_ShouldReturnMatchingLogsWithinLimit() {
+	commits := suite.commitLogs()
+	wantCommit := commits[0]
+	searchKey := wantCommit.Id().String()[0:8]
+
+	want := bindWithModel([]git.Commit{wantCommit})
+
+	suite.mockListLogs.EXPECT().Get().Return(suite.commitLogsExceedingLimit(wantCommit), nil)
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return([]*model.GitCommitFileResult{{}}, nil).MaxTimes(constants.SearchLimit)
+
+	got, err := suite.searchLogs.GetMatchingLogs("hash", searchKey)
+
+	suite.Nil(err)
+	suite.Equal(*want[0].Hash, *got[0].Hash)
+	suite.Len(got, constants.SearchLimit)
+}
+
+func bindWithModel(commits []git.Commit) []*model.GitCommits {
+	var mappedCommits []*model.GitCommits
+
+	for _, commit := range commits {
+		wantedHash := commit.Id().String()
+		wantedAuthor := commit.Author().Name
+		wantedTime := commit.Author().When.String()
+		wantedMessage := strings.TrimSpace(commit.Message())
+		wantedFileCount := 1
+
+		mappedCommits = append(mappedCommits, &model.GitCommits{
+			Hash:             &wantedHash,
+			Author:           &wantedAuthor,
+			CommitTime:       &wantedTime,
+			CommitMessage:    &wantedMessage,
+			CommitFilesCount: &wantedFileCount,
+		})
+	}
+
+	return mappedCommits
+}
+
+func (suite *SearchLogsTestSuite) commitLogs() []git.Commit {
+	commits, err := suite.listAllLogs.Get()
+	if err != nil {
+		return nil
+	}
+
+	return commits
+}
+
+func (suite *SearchLogsTestSuite) commitLogsExceedingLimit(commit git.Commit) []git.Commit {
+	var commits []git.Commit
+	limit := constants.SearchLimit * 2
+
+	for i := 0; i < limit; i++ {
+		commits = append(commits, commit)
+	}
+
+	return commits
+}
diff --git a/git/git_commit_log_search.go b/git/git_commit_log_search.go
deleted file mode 100644
index ffde1dc..0000000
--- a/git/git_commit_log_search.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-	"regexp"
-)
-
-type SearchCommitInterface interface {
-	SearchCommitLogs() []*model.GitCommits
-}
-
-type SearchCommitStruct struct {
-	Repo       *git2go.Repository
-	SearchType string
-	SearchKey  string
-}
-
-// SearchCommitLogs searches for the required commits matching the searchKey with the respective searchType
-//
-// The UI uses 'message' as the default search type to look up based on commit messages
-func (s SearchCommitStruct) SearchCommitLogs() []*model.GitCommits {
-	var searchResult []*model.GitCommits
-
-	repo := s.Repo
-
-	searchKey := s.SearchKey
-	searchType := s.SearchType
-
-	walker, walkerErr := repo.Walk()
-
-	if walkerErr == nil {
-		logger.Log(fmt.Sprintf("Searching commit logs with %s for -> %s", searchType, searchKey), global.StatusInfo)
-		_ = walker.PushHead()
-		_ = walker.Iterate(func(commit *git2go.Commit) bool {
-			if len(searchResult) == 10 {
-				return false
-			}
-
-			switch searchType {
-			case "message":
-				if isMatch, _ := regexp.MatchString(searchKey, commit.Message()); isMatch {
-					commitLog := commitOrganizer(repo, []git2go.Commit{*commit})
-					searchResult = append(searchResult, commitLog...)
-				}
-				break
-			case "hash":
-				if isMatch, _ := regexp.MatchString(searchKey, commit.Id().String()); isMatch {
-					commitLog := commitOrganizer(repo, []git2go.Commit{*commit})
-					searchResult = append(searchResult, commitLog...)
-				}
-				break
-			case "user":
-				if isMatch, _ := regexp.MatchString(searchKey, commit.Author().Name); isMatch {
-					commitLog := commitOrganizer(repo, []git2go.Commit{*commit})
-					searchResult = append(searchResult, commitLog...)
-				}
-				break
-			}
-			return true
-		})
-	} else {
-		logger.Log(walkerErr.Error(), global.StatusError)
-		return searchResult
-	}
-	return searchResult
-}

From c53b1d3b53e2da617f70d157a9911933a59f1a1d Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 29 Jul 2021 23:33:05 +0530
Subject: [PATCH 071/148] add new api for looking up a commit based on commit
 hash

---
 git/commit/errors.go                 | 15 +++---
 git/commit/git_commit_lookup.go      | 35 +++++++++++++
 git/commit/git_commit_lookup_test.go | 74 ++++++++++++++++++++++++++++
 3 files changed, 118 insertions(+), 6 deletions(-)
 create mode 100644 git/commit/git_commit_lookup.go
 create mode 100644 git/commit/git_commit_lookup_test.go

diff --git a/git/commit/errors.go b/git/commit/errors.go
index 4f2b4a9..8622db8 100644
--- a/git/commit/errors.go
+++ b/git/commit/errors.go
@@ -7,12 +7,15 @@ type Error struct {
 }
 
 var (
-	ChangeError              = Error{ErrorCode: "COMMIT_FAILED", ErrorString: "Failed to commit the new changes"}
-	LogsError                = Error{ErrorCode: "LIST_COMMIT_LOGS_FAILED", ErrorString: "Failed to list the commit logs for the repo"}
-	FileHistoryError         = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_FAILED", ErrorString: "Failed to get the list of file changes for the commit"}
-	FileHistoryNoParentError = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_NO_PARENT", ErrorString: "The HEAD commit is the only commit in the repo and has no previous histories"}
-	FileHistoryTreeError     = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_INVALID_TREE", ErrorString: "The commit tree is invalid"}
-	InvalidSearchCategory    = Error{ErrorCode: "COMMIT_SEARCH_INVALID_SEARCH_TYPE", ErrorString: "The selected search category is invalid"}
+	ChangeError                = Error{ErrorCode: "COMMIT_FAILED", ErrorString: "Failed to commit the new changes"}
+	LogsError                  = Error{ErrorCode: "LIST_COMMIT_LOGS_FAILED", ErrorString: "Failed to list the commit logs for the repo"}
+	FileHistoryError           = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_FAILED", ErrorString: "Failed to get the list of file changes for the commit"}
+	FileHistoryNoParentError   = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_NO_PARENT", ErrorString: "The HEAD commit is the only commit in the repo and has no previous histories"}
+	FileHistoryTreeError       = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_INVALID_TREE", ErrorString: "The commit tree is invalid"}
+	InvalidSearchCategoryError = Error{ErrorCode: "COMMIT_SEARCH_INVALID_SEARCH_TYPE", ErrorString: "The selected search category is invalid"}
+	EmptyCommitHashError       = Error{ErrorCode: "COMMIT_HASH_REQUIRED", ErrorString: "Commit hash cannot be empty"}
+	OidConversionError         = Error{ErrorCode: "INVALID_HASH_FOR_OID_CONVERSION", ErrorString: "Commit hash cannot be converted into an OID for commit lookup"}
+	CommitLookupError          = Error{ErrorCode: "COMMIT_LOOKUP_FAILED", ErrorString: "Unable to find commit with the OID"}
 )
 
 func (e Error) Error() string {
diff --git a/git/commit/git_commit_lookup.go b/git/commit/git_commit_lookup.go
new file mode 100644
index 0000000..1c31f9c
--- /dev/null
+++ b/git/commit/git_commit_lookup.go
@@ -0,0 +1,35 @@
+package commit
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type Lookup interface {
+	WithReferenceId(string) (middleware.Commit, error)
+}
+
+type lookup struct {
+	repo middleware.Repository
+}
+
+func (l lookup) WithReferenceId(commitHash string) (middleware.Commit, error) {
+	oid, oidErr := git2go.NewOid(commitHash)
+	if oidErr != nil {
+		logger.Log(oidErr.Error(), global.StatusError)
+		return nil, OidConversionError
+	}
+
+	commit, err := l.repo.LookupCommit(oid)
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return nil, CommitLookupError
+	}
+
+	return middleware.NewCommit(commit), nil
+}
+
+func NewLookup(repo middleware.Repository) Lookup {
+	return lookup{repo: repo}
+}
diff --git a/git/commit/git_commit_lookup_test.go b/git/commit/git_commit_lookup_test.go
new file mode 100644
index 0000000..3fe7c8d
--- /dev/null
+++ b/git/commit/git_commit_lookup_test.go
@@ -0,0 +1,74 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type CommitLookupTestSuite struct {
+	suite.Suite
+	repo           middleware.Repository
+	mockController *gomock.Controller
+	mockRepo       *mocks.MockRepository
+	commitHash     string
+	lookup         Lookup
+}
+
+func TestCommitLookupTestSuite(t *testing.T) {
+	suite.Run(t, new(CommitLookupTestSuite))
+}
+
+func (suite *CommitLookupTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	commits, _ := NewListAllLogs(middleware.NewRepository(r), nil, nil).Get()
+
+	suite.commitHash = commits[0].Id().String()
+}
+
+func (suite *CommitLookupTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.lookup = NewLookup(suite.repo)
+}
+
+func (suite *CommitLookupTestSuite) TestWithReference_WhenCommitHashIsValid_ShouldReturnCommit() {
+	wantCommit, err := suite.lookup.WithReferenceId(suite.commitHash)
+
+	suite.Nil(err)
+	suite.Equal(suite.commitHash, wantCommit.Id().String())
+}
+
+func (suite *CommitLookupTestSuite) TestWithReference_WhenCommitHashIsInValid_ShouldReturnError() {
+	_, err := suite.lookup.WithReferenceId("INVALID_HASH")
+
+	suite.NotNil(err)
+	suite.Equal(OidConversionError, err)
+}
+
+func (suite *CommitLookupTestSuite) TestWithReference_WhenCommitIsNotPresentInTheRepo_ShouldReturnError() {
+	suite.lookup = NewLookup(suite.mockRepo)
+
+	oid, _ := git2go.NewOid("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3")
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, errors.New("LOOKUP_ERR"))
+
+	_, err := suite.lookup.WithReferenceId("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3")
+
+	suite.NotNil(err)
+	suite.Equal(CommitLookupError, err)
+}

From 4e96e09dcd6e45976a8b4657e011d7a10805a568 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 29 Jul 2021 23:40:34 +0530
Subject: [PATCH 072/148] remove mapper from commit interface

---
 git/commit/commit.go | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/git/commit/commit.go b/git/commit/commit.go
index 8ab7e3f..e608700 100644
--- a/git/commit/commit.go
+++ b/git/commit/commit.go
@@ -9,6 +9,9 @@ var logger global.Logger
 
 type Commit interface {
 	GitCommitChange() (string, error)
+	GitTotalCommits() int
+	GitCommitLogs() ([]*model.GitCommits, error)
+	GitCommitFileHistory(string) ([]*model.GitCommitFileResult, error)
 }
 
 type Operation struct {
@@ -16,7 +19,7 @@ type Operation struct {
 	Total       Total
 	ListAllLogs ListAllLogs
 	FileHistory FileHistory
-	Mapper      Mapper
+	Lookup      Lookup
 }
 
 func (c Operation) GitCommitChange() (string, error) {
@@ -41,5 +44,18 @@ func (c Operation) GitCommitLogs() ([]*model.GitCommits, error) {
 		return nil, LogsError
 	}
 
-	return c.Mapper.Map(commits), nil
+	return NewMapper(c.FileHistory).Map(commits), nil
+}
+
+func (c Operation) GitCommitFileHistory(commitHash string) ([]*model.GitCommitFileResult, error) {
+	if commitHash == "" {
+		return nil, EmptyCommitHashError
+	}
+
+	commit, err := c.Lookup.WithReferenceId(commitHash)
+	if err != nil {
+		return nil, err
+	}
+
+	return c.FileHistory.Get(commit)
 }

From cce854f4dcedd7cbe95450f7782ce1b3e487b08f Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 29 Jul 2021 23:50:16 +0530
Subject: [PATCH 073/148] add new controllers for commit api

---
 controller/commit_file_history.go   | 40 ++++++++++++++++
 controller/commit_logs.go           | 71 +++++++++++++++++++++++++++++
 controller/commit_search_logs.go    | 45 ++++++++++++++++++
 controller/controller.go            |  5 ++
 git/commit/commit.go                |  6 +++
 git/commit/git_commit_log_search.go |  2 +-
 6 files changed, 168 insertions(+), 1 deletion(-)
 create mode 100644 controller/commit_file_history.go
 create mode 100644 controller/commit_logs.go
 create mode 100644 controller/commit_search_logs.go
 create mode 100644 controller/controller.go

diff --git a/controller/commit_file_history.go b/controller/commit_file_history.go
new file mode 100644
index 0000000..1165656
--- /dev/null
+++ b/controller/commit_file_history.go
@@ -0,0 +1,40 @@
+package controller
+
+import (
+	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type CommitFileHistoryController interface {
+	GetCommitFileHistory() ([]*model.GitCommitFileResult, error)
+}
+
+type commitFileHistoryController struct {
+	repoId     string
+	commitHash string
+}
+
+func (c commitFileHistoryController) GetCommitFileHistory() ([]*model.GitCommitFileResult, error) {
+	repoChan := make(chan git.RepoDetails)
+	var repoObject git.RepoInterface
+	repoObject = git.RepoStruct{RepoId: c.repoId}
+	go repoObject.Repo(repoChan)
+	repo := <-repoChan
+
+	repository := middleware.NewRepository(repo.GitRepo)
+
+	fileHistory := commit.NewFileHistory(repository)
+	commitLookup := commit.NewLookup(repository)
+	operation := commit.Operation{FileHistory: fileHistory, Lookup: commitLookup}
+
+	return operation.GitCommitFileHistory(c.commitHash)
+}
+
+func NewCommitFileHistoryController(repoId string, commitHash string) CommitFileHistoryController {
+	return commitFileHistoryController{
+		repoId:     repoId,
+		commitHash: commitHash,
+	}
+}
diff --git a/controller/commit_logs.go b/controller/commit_logs.go
new file mode 100644
index 0000000..be300ba
--- /dev/null
+++ b/controller/commit_logs.go
@@ -0,0 +1,71 @@
+package controller
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type CommitLogController interface {
+	GetCommitLogs() (*model.GitCommitLogResults, error)
+}
+type commitLogController struct {
+	repoId          string
+	referenceCommit string
+}
+
+func (c commitLogController) GetCommitLogs() (*model.GitCommitLogResults, error) {
+	repoChan := make(chan git.RepoDetails)
+	var repoObject git.RepoInterface
+	repoObject = git.RepoStruct{RepoId: c.repoId}
+	go repoObject.Repo(repoChan)
+	repo := <-repoChan
+
+	repository := middleware.NewRepository(repo.GitRepo)
+
+	list := commit.NewListAllLogs(repository, nil, c.referenceId())
+	total := commit.NewTotalCommits(list)
+	fileHistory := commit.NewFileHistory(repository)
+
+	operation := commit.Operation{
+		ListAllLogs: list,
+		Total:       total,
+		FileHistory: fileHistory,
+	}
+
+	commits, err := operation.GitCommitLogs()
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return nil, err
+	}
+	totalCommits := operation.GitTotalCommits()
+
+	return &model.GitCommitLogResults{
+		TotalCommits: &totalCommits,
+		Commits:      commits,
+	}, nil
+}
+
+func (c commitLogController) referenceId() *git2go.Oid {
+	if c.referenceCommit == "" {
+		return nil
+	}
+
+	referenceId, oidErr := git2go.NewOid(c.referenceCommit)
+	if oidErr != nil {
+		logger.Log(oidErr.Error(), global.StatusError)
+		return nil
+	}
+
+	return referenceId
+}
+
+func NewCommitLogController(repoId string, referenceCommit string) CommitLogController {
+	return commitLogController{
+		repoId:          repoId,
+		referenceCommit: referenceCommit,
+	}
+}
diff --git a/controller/commit_search_logs.go b/controller/commit_search_logs.go
new file mode 100644
index 0000000..87b85e3
--- /dev/null
+++ b/controller/commit_search_logs.go
@@ -0,0 +1,45 @@
+package controller
+
+import (
+	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type CommitLogSearchController interface {
+	GetMatchingCommits() ([]*model.GitCommits, error)
+}
+
+type commitLogSearchController struct {
+	repoId     string
+	searchType string
+	searchKey  string
+}
+
+func (c commitLogSearchController) GetMatchingCommits() ([]*model.GitCommits, error) {
+	repoChan := make(chan git.RepoDetails)
+	var repoObject git.RepoInterface
+	repoObject = git.RepoStruct{RepoId: c.repoId}
+	go repoObject.Repo(repoChan)
+	repo := <-repoChan
+
+	repository := middleware.NewRepository(repo.GitRepo)
+
+	list := commit.NewListAllLogs(repository, nil, nil)
+	fileHistory := commit.NewFileHistory(repository)
+	mapper := commit.NewMapper(fileHistory)
+	searchLogs := commit.NewSearchLogs(repository, list, mapper)
+
+	operation := commit.Operation{SearchLogs: searchLogs}
+
+	return operation.GitSearchCommitLogs(c.searchType, c.searchKey)
+}
+
+func NewCommitLogSearchController(repoId string, searchType string, searchKey string) CommitLogSearchController {
+	return commitLogSearchController{
+		repoId:     repoId,
+		searchType: searchType,
+		searchKey:  searchKey,
+	}
+}
diff --git a/controller/controller.go b/controller/controller.go
new file mode 100644
index 0000000..9e6da75
--- /dev/null
+++ b/controller/controller.go
@@ -0,0 +1,5 @@
+package controller
+
+import "github.com/neel1996/gitconvex/global"
+
+var logger global.Logger
diff --git a/git/commit/commit.go b/git/commit/commit.go
index e608700..5382e4b 100644
--- a/git/commit/commit.go
+++ b/git/commit/commit.go
@@ -12,6 +12,7 @@ type Commit interface {
 	GitTotalCommits() int
 	GitCommitLogs() ([]*model.GitCommits, error)
 	GitCommitFileHistory(string) ([]*model.GitCommitFileResult, error)
+	GitSearchCommitLogs(string, string) ([]*model.GitCommits, error)
 }
 
 type Operation struct {
@@ -20,6 +21,7 @@ type Operation struct {
 	ListAllLogs ListAllLogs
 	FileHistory FileHistory
 	Lookup      Lookup
+	SearchLogs  SearchLogs
 }
 
 func (c Operation) GitCommitChange() (string, error) {
@@ -59,3 +61,7 @@ func (c Operation) GitCommitFileHistory(commitHash string) ([]*model.GitCommitFi
 
 	return c.FileHistory.Get(commit)
 }
+
+func (c Operation) GitSearchCommitLogs(searchType string, searchKey string) ([]*model.GitCommits, error) {
+	return c.SearchLogs.GetMatchingLogs(searchType, searchKey)
+}
diff --git a/git/commit/git_commit_log_search.go b/git/commit/git_commit_log_search.go
index 0c48b55..751f9bc 100644
--- a/git/commit/git_commit_log_search.go
+++ b/git/commit/git_commit_log_search.go
@@ -33,7 +33,7 @@ func (s searchLogs) GetMatchingLogs(searchType string, searchKey string) ([]*mod
 	searchFactory := search.GetSearchAction(searchType, commits)
 	if searchFactory == nil {
 		logger.Log("Invalid search category", global.StatusError)
-		return nil, InvalidSearchCategory
+		return nil, InvalidSearchCategoryError
 	}
 
 	return s.mapper.Map(searchFactory.Search(searchKey)), nil

From 451ecf2ff69a57243be36d079ae9de2697ff7939 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 29 Jul 2021 23:51:52 +0530
Subject: [PATCH 074/148] update commit api calls in gql resolver

---
 graph/generated/generated.go |  6 +--
 graph/model/models_gen.go    |  2 +-
 graph/schema.graphqls        |  2 +-
 graph/schema.resolvers.go    | 80 ++++--------------------------------
 4 files changed, 14 insertions(+), 76 deletions(-)

diff --git a/graph/generated/generated.go b/graph/generated/generated.go
index 16b6027..9f8cf23 100644
--- a/graph/generated/generated.go
+++ b/graph/generated/generated.go
@@ -1131,7 +1131,7 @@ Returns the total number of commits in the repo and the array of 10 commit log e
 """
 type GitCommitLogResults {
     "Total number of commits tracked by the branch"
-    totalCommits: Float
+    totalCommits: Int
     "Array of commit log entries ` + "`" + `gitCommits` + "`" + `"
     commits: [gitCommits]
 }
@@ -2831,9 +2831,9 @@ func (ec *executionContext) _GitCommitLogResults_totalCommits(ctx context.Contex
 	if resTmp == nil {
 		return graphql.Null
 	}
-	res := resTmp.(*float64)
+	res := resTmp.(*int)
 	fc.Result = res
-	return ec.marshalOFloat2ᚖfloat64(ctx, field.Selections, res)
+	return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _GitCommitLogResults_commits(ctx context.Context, field graphql.CollectedField, obj *model.GitCommitLogResults) (ret graphql.Marshaler) {
diff --git a/graph/model/models_gen.go b/graph/model/models_gen.go
index 125fe1e..83aed2f 100644
--- a/graph/model/models_gen.go
+++ b/graph/model/models_gen.go
@@ -41,7 +41,7 @@ type FetchResult struct {
 // Returns the total number of commits in the repo and the array of 10 commit log entries
 type GitCommitLogResults struct {
 	// Total number of commits tracked by the branch
-	TotalCommits *float64 `json:"totalCommits"`
+	TotalCommits *int `json:"totalCommits"`
 	// Array of commit log entries `gitCommits`
 	Commits []*GitCommits `json:"commits"`
 }
diff --git a/graph/schema.graphqls b/graph/schema.graphqls
index 276aab7..0ed4eda 100644
--- a/graph/schema.graphqls
+++ b/graph/schema.graphqls
@@ -66,7 +66,7 @@ Returns the total number of commits in the repo and the array of 10 commit log e
 """
 type GitCommitLogResults {
     "Total number of commits tracked by the branch"
-    totalCommits: Float
+    totalCommits: Int
     "Array of commit log entries `gitCommits`"
     commits: [gitCommits]
 }
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index 5dea3f8..87f769b 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -5,7 +5,9 @@ package graph
 
 import (
 	"context"
-	"github.com/neel1996/gitconvex/utils"
+	"github.com/neel1996/gitconvex/constants"
+	"github.com/neel1996/gitconvex/controller"
+	"github.com/neel1996/gitconvex/git/middleware"
 
 	"github.com/neel1996/gitconvex/api"
 	"github.com/neel1996/gitconvex/git"
@@ -16,6 +18,7 @@ import (
 	"github.com/neel1996/gitconvex/graph/generated"
 	"github.com/neel1996/gitconvex/graph/model"
 	initialize "github.com/neel1996/gitconvex/init"
+	"github.com/neel1996/gitconvex/utils"
 )
 
 func (r *mutationResolver) AddRepo(ctx context.Context, repoName string, repoPath string, cloneSwitch bool, repoURL *string, initSwitch bool, authOption string, sshKeyPath *string, userName *string, password *string) (*model.AddRepoParams, error) {
@@ -256,7 +259,7 @@ func (r *mutationResolver) CommitChanges(ctx context.Context, repoID string, com
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
 
-	commitChanges := commit.NewCommitChanges(repo.GitRepo, utils.GenerateNonPointerArrayFrom(commitMessage))
+	commitChanges := commit.NewCommitChanges(middleware.NewRepository(repo.GitRepo), utils.GenerateNonPointerArrayFrom(commitMessage))
 	commitOperation := commit.Operation{Changes: commitChanges}
 
 	return commitOperation.GitCommitChange()
@@ -373,7 +376,7 @@ func (r *mutationResolver) EditRemote(ctx context.Context, repoID string, remote
 
 	if repo.GitRepo == nil {
 		logger.Log("Repo is invalid", global.StatusError)
-		return &model.RemoteMutationResult{Status: global.RemoteEditError}, nil
+		return &model.RemoteMutationResult{Status: constants.RemoteEditError.Error()}, nil
 	}
 
 	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
@@ -435,84 +438,19 @@ func (r *queryResolver) GitFolderContent(ctx context.Context, repoID string, dir
 func (r *queryResolver) GitCommitLogs(ctx context.Context, repoID string, referenceCommit string) (*model.GitCommitLogResults, error) {
 	logger.Log("Initiating get commit logs request", global.StatusInfo)
 
-	repoChan := make(chan git.RepoDetails)
-	var repoObject git.RepoInterface
-	repoObject = git.RepoStruct{RepoId: repoID}
-	go repoObject.Repo(repoChan)
-	repo := <-repoChan
-
-	var commitLogObject git.CommitLogInterface
-	commitLogObject = git.CommitLogStruct{
-		Repo:            repo.GitRepo,
-		ReferenceCommit: referenceCommit,
-	}
-
-	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil {
-		logger.Log("Repo is invalid or HEAD is nil", global.StatusError)
-		return &model.GitCommitLogResults{
-			TotalCommits: nil,
-			Commits:      nil,
-		}, nil
-	}
-	return commitLogObject.CommitLogs(), nil
+	return controller.NewCommitLogController(repoID, referenceCommit).GetCommitLogs()
 }
 
 func (r *queryResolver) GitCommitFiles(ctx context.Context, repoID string, commitHash string) ([]*model.GitCommitFileResult, error) {
 	logger.Log("Initiating get commit files request", global.StatusInfo)
 
-	repoChan := make(chan git.RepoDetails)
-	var repoObject git.RepoInterface
-	repoObject = git.RepoStruct{RepoId: repoID}
-	go repoObject.Repo(repoChan)
-	repo := <-repoChan
-
-	var commitFileListObject git.CommitFileListInterface
-	commitFileListObject = git.CommitFileListStruct{
-		Repo:       repo.GitRepo,
-		CommitHash: commitHash,
-	}
-	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil {
-		logger.Log("Repo is invalid or HEAD is nil", global.StatusError)
-		return []*model.GitCommitFileResult{
-			{
-				Type:     "",
-				FileName: "",
-			},
-		}, nil
-	}
-	return commitFileListObject.CommitFileList(), nil
+	return controller.NewCommitFileHistoryController(repoID, commitHash).GetCommitFileHistory()
 }
 
 func (r *queryResolver) SearchCommitLogs(ctx context.Context, repoID string, searchType string, searchKey string) ([]*model.GitCommits, error) {
 	logger.Log("Initiating search commit logs request", global.StatusInfo)
 
-	repoChan := make(chan git.RepoDetails)
-	var repoObject git.RepoInterface
-	repoObject = git.RepoStruct{RepoId: repoID}
-	go repoObject.Repo(repoChan)
-	repo := <-repoChan
-
-	var searchCommitObject git.SearchCommitInterface
-
-	searchCommitObject = git.SearchCommitStruct{
-		Repo:       repo.GitRepo,
-		SearchType: searchType,
-		SearchKey:  searchKey,
-	}
-
-	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil {
-		logger.Log("Repo is invalid or HEAD is nil", global.StatusError)
-		return []*model.GitCommits{
-			{
-				Hash:             nil,
-				Author:           nil,
-				CommitTime:       nil,
-				CommitMessage:    nil,
-				CommitFilesCount: nil,
-			},
-		}, nil
-	}
-	return searchCommitObject.SearchCommitLogs(), nil
+	return controller.NewCommitLogSearchController(repoID, searchType, searchKey).GetMatchingCommits()
 }
 
 func (r *queryResolver) CodeFileDetails(ctx context.Context, repoID string, fileName string) (*model.CodeFileType, error) {

From 11c42223e55c2dcc72ba75efe904173acc149d00 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 29 Jul 2021 23:59:31 +0530
Subject: [PATCH 075/148] update repo status api with new commit api

---
 api/repo_status.go                       | 20 ++++++++------------
 git/commit/git_commit_log_search_test.go |  2 +-
 git/remote/remote.go                     |  3 ++-
 graph/generated/generated.go             | 21 +++------------------
 graph/model/models_gen.go                |  2 +-
 graph/schema.graphqls                    |  2 +-
 graph/schema.resolvers.go                |  6 +++---
 7 files changed, 19 insertions(+), 37 deletions(-)

diff --git a/api/repo_status.go b/api/repo_status.go
index 8632e1b..96bbafd 100644
--- a/api/repo_status.go
+++ b/api/repo_status.go
@@ -3,6 +3,8 @@ package api
 import (
 	"github.com/neel1996/gitconvex/git"
 	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/git/remote"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
@@ -15,7 +17,7 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	logger.Log("Collecting repo status information", global.StatusInfo)
 
 	repoChan := make(chan git.RepoDetails)
-	commitChan := make(chan git.AllCommitData)
+	//commitChan := make(chan commit.AllCommitData)
 	trackedFileCountChan := make(chan int)
 
 	var repoObject git.RepoInterface
@@ -91,16 +93,10 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	branches := branchList.BranchList
 	allBranches := branchList.AllBranchList
 
-	var latestCommit *string
+	listCommitLogs := commit.NewListAllLogs(middleware.NewRepository(repo), nil, nil)
+	totalCommits := commit.NewTotalCommits(listCommitLogs).Get()
 
-	var allCommitObject git.AllCommitInterface
-
-	allCommitObject = git.AllCommitStruct{Repo: repo}
-	go allCommitObject.AllCommits(commitChan)
-	commitData := <-commitChan
-	latestCommit = &commitData.LatestCommit
-	totalCommits := commitData.TotalCommits
-	totalCommitsPtr := &totalCommits
+	latestCommitMessage := commit.NewLatestMessage(middleware.NewRepository(repo)).Get()
 
 	var listFilesObject git.ListFilesInterface
 	listFilesObject = git.ListFilesStruct{
@@ -118,8 +114,8 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 		GitAllBranchList:     utils.GeneratePointerArrayFrom(allBranches),
 		GitCurrentBranch:     &currentBranch,
 		GitRemoteHost:        &remoteName,
-		GitTotalCommits:      totalCommitsPtr,
-		GitLatestCommit:      latestCommit,
+		GitTotalCommits:      &totalCommits,
+		GitLatestCommit:      &latestCommitMessage,
 		GitTotalTrackedFiles: trackedFilePtr,
 	}
 }
diff --git a/git/commit/git_commit_log_search_test.go b/git/commit/git_commit_log_search_test.go
index be6ce25..2b13bcb 100644
--- a/git/commit/git_commit_log_search_test.go
+++ b/git/commit/git_commit_log_search_test.go
@@ -107,7 +107,7 @@ func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsInvalid_Sh
 	_, err := suite.searchLogs.GetMatchingLogs("invalid", searchKey)
 
 	suite.NotNil(err)
-	suite.Equal(InvalidSearchCategory, err)
+	suite.Equal(InvalidSearchCategoryError, err)
 }
 
 func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenListLogsReturnsError_ShouldReturnError() {
diff --git a/git/remote/remote.go b/git/remote/remote.go
index 8a6e939..a476769 100644
--- a/git/remote/remote.go
+++ b/git/remote/remote.go
@@ -2,6 +2,7 @@ package remote
 
 import (
 	"errors"
+	"github.com/neel1996/gitconvex/constants"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
 )
@@ -42,7 +43,7 @@ func (r Operation) GitDeleteRemote() (*model.RemoteMutationResult, error) {
 	err := r.Delete.DeleteRemote()
 
 	if err != nil {
-		return nil, errors.New(global.RemoteDeleteError)
+		return nil, constants.RemoteDeleteError
 	}
 
 	return &model.RemoteMutationResult{Status: global.RemoteDeleteSuccess}, nil
diff --git a/graph/generated/generated.go b/graph/generated/generated.go
index 9f8cf23..d049432 100644
--- a/graph/generated/generated.go
+++ b/graph/generated/generated.go
@@ -1108,7 +1108,7 @@ type GitRepoStatusResults {
     "Remote host name based on the remote URL (E.g: https://github.com/github/repo.git -> Github)"
     gitRemoteHost: String
     "Total number of commits tracked by the current branch"
-    gitTotalCommits: Float
+    gitTotalCommits: Int
     "The latest commit (HEAD commit)"
     gitLatestCommit: String
     "Total number of files tracked by git repo"
@@ -3157,9 +3157,9 @@ func (ec *executionContext) _GitRepoStatusResults_gitTotalCommits(ctx context.Co
 	if resTmp == nil {
 		return graphql.Null
 	}
-	res := resTmp.(*float64)
+	res := resTmp.(*int)
 	fc.Result = res
-	return ec.marshalOFloat2ᚖfloat64(ctx, field.Selections, res)
+	return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _GitRepoStatusResults_gitLatestCommit(ctx context.Context, field graphql.CollectedField, obj *model.GitRepoStatusResults) (ret graphql.Marshaler) {
@@ -8702,21 +8702,6 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast
 	return graphql.MarshalBoolean(*v)
 }
 
-func (ec *executionContext) unmarshalOFloat2ᚖfloat64(ctx context.Context, v interface{}) (*float64, error) {
-	if v == nil {
-		return nil, nil
-	}
-	res, err := graphql.UnmarshalFloat(v)
-	return &res, graphql.ErrorOnPath(ctx, err)
-}
-
-func (ec *executionContext) marshalOFloat2ᚖfloat64(ctx context.Context, sel ast.SelectionSet, v *float64) graphql.Marshaler {
-	if v == nil {
-		return graphql.Null
-	}
-	return graphql.MarshalFloat(*v)
-}
-
 func (ec *executionContext) unmarshalOInt2ᚖint(ctx context.Context, v interface{}) (*int, error) {
 	if v == nil {
 		return nil, nil
diff --git a/graph/model/models_gen.go b/graph/model/models_gen.go
index 83aed2f..2f45154 100644
--- a/graph/model/models_gen.go
+++ b/graph/model/models_gen.go
@@ -70,7 +70,7 @@ type GitRepoStatusResults struct {
 	// Remote host name based on the remote URL (E.g: https://github.com/github/repo.git -> Github)
 	GitRemoteHost *string `json:"gitRemoteHost"`
 	// Total number of commits tracked by the current branch
-	GitTotalCommits *float64 `json:"gitTotalCommits"`
+	GitTotalCommits *int `json:"gitTotalCommits"`
 	// The latest commit (HEAD commit)
 	GitLatestCommit *string `json:"gitLatestCommit"`
 	// Total number of files tracked by git repo
diff --git a/graph/schema.graphqls b/graph/schema.graphqls
index 0ed4eda..2ee7888 100644
--- a/graph/schema.graphqls
+++ b/graph/schema.graphqls
@@ -43,7 +43,7 @@ type GitRepoStatusResults {
     "Remote host name based on the remote URL (E.g: https://github.com/github/repo.git -> Github)"
     gitRemoteHost: String
     "Total number of commits tracked by the current branch"
-    gitTotalCommits: Float
+    gitTotalCommits: Int
     "The latest commit (HEAD commit)"
     gitLatestCommit: String
     "Total number of files tracked by git repo"
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index 87f769b..b987be2 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -5,14 +5,14 @@ package graph
 
 import (
 	"context"
-	"github.com/neel1996/gitconvex/constants"
-	"github.com/neel1996/gitconvex/controller"
-	"github.com/neel1996/gitconvex/git/middleware"
 
 	"github.com/neel1996/gitconvex/api"
+	"github.com/neel1996/gitconvex/constants"
+	"github.com/neel1996/gitconvex/controller"
 	"github.com/neel1996/gitconvex/git"
 	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/git/remote"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/generated"

From 6acad5a30c2191b6cba16179d00bbfc22c35b2f1 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 30 Jul 2021 23:23:49 +0530
Subject: [PATCH 076/148] resolve counter bug in search actions

---
 git/commit/git_commit_log_search_test.go   | 22 +++++++++++++++++-----
 git/commit/search/commit_author_search.go  | 10 +++++++---
 git/commit/search/commit_hash_search.go    |  7 +++++--
 git/commit/search/commit_message_search.go | 10 +++++++---
 git/commit/search/search.go                |  1 +
 5 files changed, 37 insertions(+), 13 deletions(-)

diff --git a/git/commit/git_commit_log_search_test.go b/git/commit/git_commit_log_search_test.go
index 2b13bcb..e43fd1c 100644
--- a/git/commit/git_commit_log_search_test.go
+++ b/git/commit/git_commit_log_search_test.go
@@ -57,7 +57,10 @@ func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsHash_Shoul
 	want := bindWithModel([]git.Commit{wantCommit})
 
 	suite.mockListLogs.EXPECT().Get().Return(commits, nil)
-	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return([]*model.GitCommitFileResult{{}}, nil)
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return(
+		[]*model.GitCommitFileResult{{}},
+		nil,
+	).MaxTimes(constants.SearchLimit)
 
 	got, err := suite.searchLogs.GetMatchingLogs("hash", searchKey)
 
@@ -67,13 +70,16 @@ func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsHash_Shoul
 
 func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsMessage_ShouldReturnMatchingCommits() {
 	commits := suite.commitLogs()
-	wantCommit := commits[0]
+	wantCommit := commits[len(commits)-1]
 	searchKey := strings.Split(wantCommit.Message(), " ")[0]
 
 	want := bindWithModel([]git.Commit{wantCommit})
 
 	suite.mockListLogs.EXPECT().Get().Return(commits, nil)
-	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return([]*model.GitCommitFileResult{{}}, nil)
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return(
+		[]*model.GitCommitFileResult{{}},
+		nil,
+	).MaxTimes(constants.SearchLimit)
 
 	got, err := suite.searchLogs.GetMatchingLogs("message", searchKey)
 
@@ -89,7 +95,10 @@ func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsAuthor_Sho
 	want := bindWithModel([]git.Commit{wantCommit})
 
 	suite.mockListLogs.EXPECT().Get().Return(commits, nil)
-	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return([]*model.GitCommitFileResult{{}}, nil)
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return(
+		[]*model.GitCommitFileResult{{}},
+		nil,
+	).MaxTimes(constants.SearchLimit)
 
 	got, err := suite.searchLogs.GetMatchingLogs("author", searchKey)
 
@@ -130,7 +139,10 @@ func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenCommitLogsExceedsSearc
 	want := bindWithModel([]git.Commit{wantCommit})
 
 	suite.mockListLogs.EXPECT().Get().Return(suite.commitLogsExceedingLimit(wantCommit), nil)
-	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return([]*model.GitCommitFileResult{{}}, nil).MaxTimes(constants.SearchLimit)
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return(
+		[]*model.GitCommitFileResult{{}},
+		nil,
+	).MaxTimes(constants.SearchLimit)
 
 	got, err := suite.searchLogs.GetMatchingLogs("hash", searchKey)
 
diff --git a/git/commit/search/commit_author_search.go b/git/commit/search/commit_author_search.go
index 3913327..fa01726 100644
--- a/git/commit/search/commit_author_search.go
+++ b/git/commit/search/commit_author_search.go
@@ -4,6 +4,7 @@ import (
 	git "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/constants"
 	"regexp"
+	"strings"
 )
 
 type commitAuthorSearch struct {
@@ -25,16 +26,19 @@ func (h commitAuthorSearch) Search(searchKey string) []git.Commit {
 			break
 		}
 
-		if isMatch, _ := regexp.MatchString(searchKey, commit.Author().Name); isMatch {
+		if isMatch, _ := regexp.MatchString(h.ToLower(searchKey), h.ToLower(commit.Author().Name)); isMatch {
 			matchingCommits = append(matchingCommits, commit)
+			counter++
 		}
-
-		counter++
 	}
 
 	return matchingCommits
 }
 
+func (h commitAuthorSearch) ToLower(value string) string {
+	return strings.ToLower(strings.TrimSpace(value))
+}
+
 func (h commitAuthorSearch) isExceedingSearchLimit(searchLimitCounter int) bool {
 	return searchLimitCounter == constants.SearchLimit
 }
diff --git a/git/commit/search/commit_hash_search.go b/git/commit/search/commit_hash_search.go
index 374d753..e58d4ff 100644
--- a/git/commit/search/commit_hash_search.go
+++ b/git/commit/search/commit_hash_search.go
@@ -27,14 +27,17 @@ func (h commitHashSearch) Search(searchKey string) []git.Commit {
 
 		if isMatch, _ := regexp.MatchString(searchKey, commit.Id().String()); isMatch {
 			matchingCommits = append(matchingCommits, commit)
+			counter++
 		}
-
-		counter++
 	}
 
 	return matchingCommits
 }
 
+func (h commitHashSearch) ToLower(_ string) string {
+	panic("Not applicable for hash search")
+}
+
 func (h commitHashSearch) isExceedingSearchLimit(searchLimitCounter int) bool {
 	return searchLimitCounter == constants.SearchLimit
 }
diff --git a/git/commit/search/commit_message_search.go b/git/commit/search/commit_message_search.go
index a9f3a71..51fa06d 100644
--- a/git/commit/search/commit_message_search.go
+++ b/git/commit/search/commit_message_search.go
@@ -4,6 +4,7 @@ import (
 	git "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/constants"
 	"regexp"
+	"strings"
 )
 
 type commitMessageSearch struct {
@@ -25,16 +26,19 @@ func (m commitMessageSearch) Search(searchKey string) []git.Commit {
 			break
 		}
 
-		if isMatch, _ := regexp.MatchString(searchKey, commit.Message()); isMatch {
+		if isMatch, _ := regexp.MatchString(m.ToLower(searchKey), m.ToLower(commit.Message())); isMatch {
 			matchingCommits = append(matchingCommits, commit)
+			counter++
 		}
-
-		counter++
 	}
 
 	return matchingCommits
 }
 
+func (m commitMessageSearch) ToLower(value string) string {
+	return strings.ToLower(strings.TrimSpace(value))
+}
+
 func (m commitMessageSearch) isExceedingSearchLimit(searchLimitCounter int) bool {
 	return searchLimitCounter == constants.SearchLimit
 }
diff --git a/git/commit/search/search.go b/git/commit/search/search.go
index bcf3132..558813e 100644
--- a/git/commit/search/search.go
+++ b/git/commit/search/search.go
@@ -7,4 +7,5 @@ import (
 type Search interface {
 	Search(string) []git2go.Commit
 	New([]git2go.Commit) Search
+	ToLower(string) string
 }

From f918d37fbe42b1955b9edd0de309dbe24c47b43a Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 30 Jul 2021 23:24:16 +0530
Subject: [PATCH 077/148] add no commit logger in mapper to report if the
 commits are empty

---
 git/commit/git_commit_log_mapper.go | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/git/commit/git_commit_log_mapper.go b/git/commit/git_commit_log_mapper.go
index 5d38dd9..954508e 100644
--- a/git/commit/git_commit_log_mapper.go
+++ b/git/commit/git_commit_log_mapper.go
@@ -27,6 +27,11 @@ type mapperCommitType struct {
 func (m mapper) Map(commits []git2go.Commit) []*model.GitCommits {
 	var mappedCommits []*model.GitCommits
 
+	if len(commits) == 0 {
+		logger.Log("No commits received for mapping", global.StatusWarning)
+		return nil
+	}
+
 	for _, commit := range commits {
 		commitFields := m.commitFields(commit)
 

From e5f6112c65d4b67cd7e652562feb3e406c0f0604 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 30 Jul 2021 23:24:35 +0530
Subject: [PATCH 078/148] update test setup function to use new commit change
 api

---
 git/branch/git_branch_compare_test.go | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
index 868de04..a6c2f85 100644
--- a/git/branch/git_branch_compare_test.go
+++ b/git/branch/git_branch_compare_test.go
@@ -5,6 +5,7 @@ import (
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git"
 	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/stretchr/testify/suite"
 	"io/ioutil"
@@ -122,5 +123,5 @@ func (suite *BranchCompareTestSuite) stageAndCommitTestFile() {
 		FileItem: suite.testFile,
 	}.StageItem()
 
-	_ = commit.NewCommitChanges(suite.repo, []string{"Branch compare test commit"}).Add()
+	_ = commit.NewCommitChanges(middleware.NewRepository(suite.repo), []string{"Branch compare test commit"}).Add()
 }

From 83446b5b076ebd00385102c718984c02c31eb327 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 30 Jul 2021 23:35:39 +0530
Subject: [PATCH 079/148] fix test issue for file history api

---
 git/commit/git_commit_file_history_test.go | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/git/commit/git_commit_file_history_test.go b/git/commit/git_commit_file_history_test.go
index 41d48b2..98298d8 100644
--- a/git/commit/git_commit_file_history_test.go
+++ b/git/commit/git_commit_file_history_test.go
@@ -40,9 +40,9 @@ func (suite *FileHistoryTestSuite) SetupTest() {
 
 func (suite *FileHistoryTestSuite) TestGet_WhenRepoHasMoreThanOneCommit_ShouldReturnDiffForChosenCommit() {
 	suite.fileHistory = NewFileHistory(suite.repo)
+	commitLogs := suite.commitLogs()
 
-	head, _ := suite.repo.Head()
-	commit, _ := suite.repo.LookupCommit(head.Target())
+	commit, _ := suite.repo.LookupCommit(commitLogs[len(commitLogs)-2].Id())
 
 	gotHistory, err := suite.fileHistory.Get(middleware.NewCommit(commit))
 
@@ -109,3 +109,12 @@ func (suite *FileHistoryTestSuite) TestGet_WhenDiffNumDeltaIsZero_ShouldReturnEr
 	suite.NotNil(err)
 	suite.Equal(FileHistoryError, err)
 }
+
+func (suite *FileHistoryTestSuite) commitLogs() []git2go.Commit {
+	commits, err := NewListAllLogs(suite.repo, nil, nil).Get()
+	if err != nil {
+		return nil
+	}
+
+	return commits
+}

From bbc8a4492c31bbf67212fd328d53df5fa6cf705c Mon Sep 17 00:00:00 2001
From: Neel <neelusenthil1996@gmail.com>
Date: Sun, 1 Aug 2021 23:19:29 +0530
Subject: [PATCH 080/148] add new middleware interface for remotes

---
 git/middleware/remotes.go    | 31 +++++++++++++++++++++++++++++++
 git/middleware/repository.go |  5 +++++
 2 files changed, 36 insertions(+)
 create mode 100644 git/middleware/remotes.go

diff --git a/git/middleware/remotes.go b/git/middleware/remotes.go
new file mode 100644
index 0000000..25ff7e0
--- /dev/null
+++ b/git/middleware/remotes.go
@@ -0,0 +1,31 @@
+package middleware
+
+import git "github.com/libgit2/git2go/v31"
+
+type Remotes interface {
+	Create(string, string) (*git.Remote, error)
+	Get() git.RemoteCollection
+	Delete(string) error
+}
+
+type remotes struct {
+	git.RemoteCollection
+}
+
+func (r remotes) Create(name string, url string) (*git.Remote, error) {
+	return r.RemoteCollection.Create(name, url)
+}
+
+func (r remotes) Get() git.RemoteCollection {
+	return r.RemoteCollection
+}
+
+func (r remotes) Delete(name string) error {
+	return r.RemoteCollection.Delete(name)
+}
+
+func NewRemotes(remoteCollection git.RemoteCollection) Remotes {
+	return remotes{
+		RemoteCollection: remoteCollection,
+	}
+}
diff --git a/git/middleware/repository.go b/git/middleware/repository.go
index f2b8566..85b6403 100644
--- a/git/middleware/repository.go
+++ b/git/middleware/repository.go
@@ -3,6 +3,7 @@ package middleware
 import git "github.com/libgit2/git2go/v31"
 
 type Repository interface {
+	Remotes() Remotes
 	Walk() (RevWalk, error)
 	Head() (Reference, error)
 	LookupCommit(oid *git.Oid) (*git.Commit, error)
@@ -17,6 +18,10 @@ type repository struct {
 	repo *git.Repository
 }
 
+func (r repository) Remotes() Remotes {
+	return NewRemotes(r.repo.Remotes)
+}
+
 func (r repository) CreateCommit(s string, signature *git.Signature, signature2 *git.Signature,
 	message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error) {
 	return r.repo.CreateCommit(s, signature, signature2, message, tree, parents...)

From a8ad43478bdf2606393994bd4eee3a0502e04714 Mon Sep 17 00:00:00 2001
From: Neel <neelusenthil1996@gmail.com>
Date: Thu, 5 Aug 2021 23:58:16 +0530
Subject: [PATCH 081/148] update repo with middleware repo object in for remote
 package apis

---
 api/repo_status.go                     |  6 ++--
 git/middleware/remotes.go              | 15 ++++++++++
 git/remote/git_remote_add.go           |  8 +++---
 git/remote/git_remote_add_test.go      |  9 +++---
 git/remote/git_remote_delete.go        |  8 +++---
 git/remote/git_remote_delete_test.go   | 13 ++++-----
 git/remote/git_remote_edit.go          | 11 ++++---
 git/remote/git_remote_edit_test.go     | 40 ++++++++++++++------------
 git/remote/git_remote_list.go          | 10 +++----
 git/remote/git_remote_list_test.go     | 20 +++++++------
 git/remote/git_remote_remote_name.go   |  6 ++--
 git/remote/git_remote_url_data.go      |  6 ++--
 git/remote/git_remote_url_data_test.go | 28 +++++++++---------
 git/remote/remote_validation.go        |  7 +++--
 git/remote/remote_validation_test.go   | 19 ++++++++----
 init/init_remote.go                    |  4 ++-
 mocks/mock_repository.go               | 14 +++++++++
 17 files changed, 135 insertions(+), 89 deletions(-)

diff --git a/api/repo_status.go b/api/repo_status.go
index 96bbafd..2124eb7 100644
--- a/api/repo_status.go
+++ b/api/repo_status.go
@@ -49,7 +49,9 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	)
 	remoteURL = &tempRemote
 
-	remoteUrlList := remote.NewRemoteUrlData(repo)
+	repoForRemote := middleware.NewRepository(repo)
+
+	remoteUrlList := remote.NewRemoteUrlData(repoForRemote)
 	listRemoteUrl := remote.Operation{ListRemoteUrl: remoteUrlList}
 
 	remotes, remoteErr := listRemoteUrl.GitGetAllRemoteUrl()
@@ -59,7 +61,7 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	}
 
 	if len(remotes) > 0 && *remotes[0] != "" {
-		remoteNameObject := remote.NewGetRemoteName(repo, *remotes[0])
+		remoteNameObject := remote.NewGetRemoteName(repoForRemote, *remotes[0])
 		remoteName = remoteNameObject.GetRemoteNameWithUrl()
 		sRemote := strings.Split(*remotes[0], "/")
 		repoName = &sRemote[len(sRemote)-1]
diff --git a/git/middleware/remotes.go b/git/middleware/remotes.go
index 25ff7e0..9fab02a 100644
--- a/git/middleware/remotes.go
+++ b/git/middleware/remotes.go
@@ -6,6 +6,9 @@ type Remotes interface {
 	Create(string, string) (*git.Remote, error)
 	Get() git.RemoteCollection
 	Delete(string) error
+	List() ([]string, error)
+	SetUrl(string, string) error
+	Lookup(string) (*git.Remote, error)
 }
 
 type remotes struct {
@@ -24,6 +27,18 @@ func (r remotes) Delete(name string) error {
 	return r.RemoteCollection.Delete(name)
 }
 
+func (r remotes) List() ([]string, error) {
+	return r.RemoteCollection.List()
+}
+
+func (r remotes) SetUrl(name string, url string) error {
+	return r.RemoteCollection.SetUrl(name, url)
+}
+
+func (r remotes) Lookup(name string) (*git.Remote, error) {
+	return r.RemoteCollection.Lookup(name)
+}
+
 func NewRemotes(remoteCollection git.RemoteCollection) Remotes {
 	return remotes{
 		RemoteCollection: remoteCollection,
diff --git a/git/remote/git_remote_add.go b/git/remote/git_remote_add.go
index 15a8864..ebff9f0 100644
--- a/git/remote/git_remote_add.go
+++ b/git/remote/git_remote_add.go
@@ -2,7 +2,7 @@ package remote
 
 import (
 	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 )
 
@@ -11,7 +11,7 @@ type Add interface {
 }
 
 type addRemote struct {
-	repo       *git2go.Repository
+	repo       middleware.Repository
 	remoteName string
 	remoteURL  string
 }
@@ -23,7 +23,7 @@ func (a addRemote) NewRemote() error {
 		return validationErr
 	}
 
-	remote, err := a.repo.Remotes.Create(a.remoteName, a.remoteURL)
+	remote, err := a.repo.Remotes().Create(a.remoteName, a.remoteURL)
 	if err != nil {
 		logger.Log("Remote addition Failed -> "+err.Error(), global.StatusError)
 		return err
@@ -42,7 +42,7 @@ func (a addRemote) validateRemoteFields() error {
 	return nil
 }
 
-func NewAddRemote(repo *git2go.Repository, remoteName string, remoteURL string) Add {
+func NewAddRemote(repo middleware.Repository, remoteName string, remoteURL string) Add {
 	return addRemote{
 		repo:       repo,
 		remoteName: remoteName,
diff --git a/git/remote/git_remote_add_test.go b/git/remote/git_remote_add_test.go
index 03ca827..a24f16a 100644
--- a/git/remote/git_remote_add_test.go
+++ b/git/remote/git_remote_add_test.go
@@ -3,6 +3,7 @@ package remote
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/stretchr/testify/suite"
 	"os"
@@ -11,7 +12,7 @@ import (
 
 type RemoteAddTestSuite struct {
 	suite.Suite
-	repo       *git2go.Repository
+	repo       middleware.Repository
 	remoteName string
 	remoteUrl  string
 	addRemote  Add
@@ -26,7 +27,7 @@ func (suite *RemoteAddTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.repo = r
+	suite.repo = middleware.NewRepository(r)
 	suite.remoteName = "new_origin"
 	suite.remoteUrl = "https://github.com/neel1996/gitconvex-test.git"
 	suite.addRemote = NewAddRemote(suite.repo, suite.remoteName, suite.remoteUrl)
@@ -40,7 +41,7 @@ func (suite *RemoteAddTestSuite) TearDownSuite() {
 	}
 }
 
-func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenNewRemoteIsAdded_ShouldReturnNoError() {
+func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenNewRemoteIsAdded_ShouldReturnNil() {
 	err := suite.addRemote.NewRemote()
 
 	suite.Nil(err)
@@ -73,7 +74,7 @@ func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteUrlIsEmpty_ShouldRet
 func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteCreationFails_ShouldReturnError() {
 	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
-	suite.addRemote = NewAddRemote(r, "new_origin", "https://github.com/neel1996/gitconvex-test.git")
+	suite.addRemote = NewAddRemote(middleware.NewRepository(r), "new_origin", "https://github.com/neel1996/gitconvex-test.git")
 
 	err := suite.addRemote.NewRemote()
 
diff --git a/git/remote/git_remote_delete.go b/git/remote/git_remote_delete.go
index db43df8..a454a1c 100644
--- a/git/remote/git_remote_delete.go
+++ b/git/remote/git_remote_delete.go
@@ -2,7 +2,7 @@ package remote
 
 import (
 	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 )
 
@@ -11,7 +11,7 @@ type Delete interface {
 }
 
 type deleteRemote struct {
-	repo       *git2go.Repository
+	repo       middleware.Repository
 	remoteName string
 }
 
@@ -32,7 +32,7 @@ func (d deleteRemote) DeleteRemote() error {
 }
 
 func (d *deleteRemote) deleteSelectedRemote(remoteEntry string) error {
-	err := d.repo.Remotes.Delete(remoteEntry)
+	err := d.repo.Remotes().Delete(remoteEntry)
 	if err != nil {
 		logger.Log(err.Error(), global.StatusError)
 		return err
@@ -42,7 +42,7 @@ func (d *deleteRemote) deleteSelectedRemote(remoteEntry string) error {
 	return nil
 }
 
-func NewDeleteRemote(repo *git2go.Repository, remoteName string) Delete {
+func NewDeleteRemote(repo middleware.Repository, remoteName string) Delete {
 	return deleteRemote{
 		repo:       repo,
 		remoteName: remoteName,
diff --git a/git/remote/git_remote_delete_test.go b/git/remote/git_remote_delete_test.go
index 5d590b0..0d846fe 100644
--- a/git/remote/git_remote_delete_test.go
+++ b/git/remote/git_remote_delete_test.go
@@ -3,6 +3,7 @@ package remote
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/stretchr/testify/suite"
 	"os"
 	"testing"
@@ -10,7 +11,7 @@ import (
 
 type RemoteDeleteTestSuite struct {
 	suite.Suite
-	repo         *git2go.Repository
+	repo         middleware.Repository
 	remoteName   string
 	deleteRemote Delete
 }
@@ -25,7 +26,7 @@ func (suite *RemoteDeleteTestSuite) SetupSuite() {
 		fmt.Println(err)
 	}
 	suite.remoteName = "new_origin"
-	_ = NewAddRemote(r, suite.remoteName, "remote://some_url").NewRemote()
+	_ = NewAddRemote(middleware.NewRepository(r), suite.remoteName, "remote://some_url").NewRemote()
 }
 
 func (suite *RemoteDeleteTestSuite) SetupTest() {
@@ -33,9 +34,9 @@ func (suite *RemoteDeleteTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.repo = r
+	suite.repo = middleware.NewRepository(r)
 	suite.remoteName = "new_origin"
-	suite.deleteRemote = NewDeleteRemote(r, suite.remoteName)
+	suite.deleteRemote = NewDeleteRemote(suite.repo, suite.remoteName)
 }
 
 func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenNewRemoteIsDeleted_ShouldReturnNoError() {
@@ -61,9 +62,7 @@ func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteNameIsEmpty_Sh
 }
 
 func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteDeletionFails_ShouldReturnError() {
-	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-
-	suite.deleteRemote = NewDeleteRemote(r, "new_origin")
+	suite.deleteRemote = NewDeleteRemote(suite.repo, "new_origin")
 
 	err := suite.deleteRemote.DeleteRemote()
 
diff --git a/git/remote/git_remote_edit.go b/git/remote/git_remote_edit.go
index 7430593..15a8130 100644
--- a/git/remote/git_remote_edit.go
+++ b/git/remote/git_remote_edit.go
@@ -3,7 +3,7 @@ package remote
 import (
 	"errors"
 	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 )
 
@@ -12,7 +12,7 @@ type Edit interface {
 }
 
 type editRemote struct {
-	repo       *git2go.Repository
+	repo       middleware.Repository
 	remoteName string
 	remoteURL  string
 }
@@ -26,8 +26,7 @@ func (e editRemote) EditRemote() error {
 		return validationErr
 	}
 
-	remoteCollection := repo.Remotes
-	_, listErr := remoteCollection.List()
+	_, listErr := repo.Remotes().List()
 
 	if listErr != nil {
 		logger.Log(listErr.Error(), global.StatusError)
@@ -39,7 +38,7 @@ func (e editRemote) EditRemote() error {
 		return remoteAvailabilityErr
 	}
 
-	err := repo.Remotes.SetUrl(e.remoteName, e.remoteURL)
+	err := repo.Remotes().SetUrl(e.remoteName, e.remoteURL)
 	if err != nil {
 		logger.Log(err.Error(), global.StatusError)
 		return err
@@ -69,7 +68,7 @@ func (e editRemote) isRemotePresentInRepo() error {
 	return err
 }
 
-func NewEditRemote(repo *git2go.Repository, remoteName string, remoteURL string) Edit {
+func NewEditRemote(repo middleware.Repository, remoteName string, remoteURL string) Edit {
 	return editRemote{
 		repo:       repo,
 		remoteName: remoteName,
diff --git a/git/remote/git_remote_edit_test.go b/git/remote/git_remote_edit_test.go
index 2a0a961..3ee97ad 100644
--- a/git/remote/git_remote_edit_test.go
+++ b/git/remote/git_remote_edit_test.go
@@ -2,21 +2,24 @@ package remote
 
 import (
 	"fmt"
+	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
-	"path/filepath"
 	"testing"
 )
 
 type RemoteEditTestSuite struct {
 	suite.Suite
-	repo       *git2go.Repository
-	noHeadRepo *git2go.Repository
-	remoteName string
-	remoteUrl  string
-	validation Validation
-	editRemote Edit
+	repo           middleware.Repository
+	mockController *gomock.Controller
+	mockRepo       *mocks.MockRepository
+	remoteName     string
+	remoteUrl      string
+	validation     Validation
+	editRemote     Edit
 }
 
 func TestRemoteEditTestSuite(t *testing.T) {
@@ -28,17 +31,18 @@ func (suite *RemoteEditTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
-	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
 
-	suite.repo = r
-	suite.noHeadRepo = noHeadRepo
+	suite.repo = middleware.NewRepository(r)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
 	suite.remoteName = "origin"
 	suite.remoteUrl = "https://github.com/neel1996/gitconvex-test.git"
-	suite.editRemote = NewEditRemote(r, suite.remoteName, suite.remoteUrl)
+	suite.editRemote = NewEditRemote(suite.mockRepo, suite.remoteName, suite.remoteUrl)
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsEdited_ShouldReturnNil() {
+	suite.editRemote = NewEditRemote(suite.repo, suite.remoteName, suite.remoteUrl)
+
 	wantErr := suite.editRemote.EditRemote()
 
 	suite.Nil(wantErr)
@@ -53,9 +57,7 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoIsNil_ShouldReturnError
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteCollectionIsNil_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(&git2go.Repository{
-		Remotes: git2go.RemoteCollection{},
-	}, suite.remoteName, suite.remoteUrl)
+	suite.editRemote = NewEditRemote(suite.mockRepo, suite.remoteName, suite.remoteUrl)
 
 	wantErr := suite.editRemote.EditRemote()
 
@@ -63,7 +65,7 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteCollectionIsNil_Shoul
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteNameIsEmpty_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(suite.repo, "", suite.remoteUrl)
+	suite.editRemote = NewEditRemote(suite.mockRepo, "", suite.remoteUrl)
 
 	wantErr := suite.editRemote.EditRemote()
 
@@ -71,7 +73,7 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteNameIsEmpty_ShouldRet
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteUrlIsEmpty_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(suite.repo, suite.remoteName, "")
+	suite.editRemote = NewEditRemote(suite.mockRepo, suite.remoteName, "")
 
 	wantErr := suite.editRemote.EditRemote()
 
@@ -79,7 +81,7 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteUrlIsEmpty_ShouldRetu
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoHasNoRemotes_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(suite.noHeadRepo, suite.remoteName, suite.remoteUrl)
+	suite.editRemote = NewEditRemote(suite.mockRepo, suite.remoteName, suite.remoteUrl)
 
 	wantErr := suite.editRemote.EditRemote()
 
@@ -87,7 +89,7 @@ func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoHasNoRemotes_ShouldRetu
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsNotPresent_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(suite.repo, "no_exists_remote", suite.remoteUrl)
+	suite.editRemote = NewEditRemote(suite.mockRepo, "no_exists_remote", suite.remoteUrl)
 
 	wantErr := suite.editRemote.EditRemote()
 
diff --git a/git/remote/git_remote_list.go b/git/remote/git_remote_list.go
index 7e2d1e6..1567ba9 100644
--- a/git/remote/git_remote_list.go
+++ b/git/remote/git_remote_list.go
@@ -2,7 +2,7 @@ package remote
 
 import (
 	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
 )
@@ -12,7 +12,7 @@ type List interface {
 }
 
 type listRemotes struct {
-	repo *git2go.Repository
+	repo middleware.Repository
 }
 
 func (l listRemotes) GetAllRemotes() []*model.RemoteDetails {
@@ -24,14 +24,14 @@ func (l listRemotes) GetAllRemotes() []*model.RemoteDetails {
 		return nil
 	}
 
-	list, listErr := repo.Remotes.List()
+	list, listErr := repo.Remotes().List()
 	if listErr != nil {
 		logger.Log(listErr.Error(), global.StatusError)
 		return nil
 	}
 
 	for _, remoteEntry := range list {
-		remote, remoteErr := repo.Remotes.Lookup(remoteEntry)
+		remote, remoteErr := repo.Remotes().Lookup(remoteEntry)
 		if remoteErr != nil {
 			logger.Log(remoteErr.Error(), global.StatusError)
 			continue
@@ -54,6 +54,6 @@ func (l listRemotes) GetAllRemotes() []*model.RemoteDetails {
 	return remoteList
 }
 
-func NewRemoteList(repo *git2go.Repository) List {
+func NewRemoteList(repo middleware.Repository) List {
 	return listRemotes{repo: repo}
 }
diff --git a/git/remote/git_remote_list_test.go b/git/remote/git_remote_list_test.go
index 4e86447..e41a78c 100644
--- a/git/remote/git_remote_list_test.go
+++ b/git/remote/git_remote_list_test.go
@@ -2,19 +2,22 @@ package remote
 
 import (
 	"fmt"
+	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/graph/model"
+	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
-	"path/filepath"
 	"testing"
 )
 
 type ListRemoteTestSuite struct {
 	suite.Suite
-	repo       *git2go.Repository
-	noHeadRepo *git2go.Repository
-	listRemote List
+	repo           middleware.Repository
+	mockController *gomock.Controller
+	mockRepo       *mocks.MockRepository
+	listRemote     List
 }
 
 func (suite *ListRemoteTestSuite) SetupTest() {
@@ -22,11 +25,10 @@ func (suite *ListRemoteTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
-	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
 
-	suite.repo = r
-	suite.noHeadRepo = noHeadRepo
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.repo = middleware.NewRepository(r)
 	suite.listRemote = NewRemoteList(suite.repo)
 }
 
@@ -56,7 +58,7 @@ func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsNil_ShouldReturnNi
 }
 
 func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoHasNoRemotes_ShouldReturnNil() {
-	suite.listRemote = NewRemoteList(suite.noHeadRepo)
+	suite.listRemote = NewRemoteList(suite.mockRepo)
 
 	remoteList := suite.listRemote.GetAllRemotes()
 
diff --git a/git/remote/git_remote_remote_name.go b/git/remote/git_remote_remote_name.go
index f3a606c..bea1f20 100644
--- a/git/remote/git_remote_remote_name.go
+++ b/git/remote/git_remote_remote_name.go
@@ -1,7 +1,7 @@
 package remote
 
 import (
-	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 )
 
@@ -10,7 +10,7 @@ type Name interface {
 }
 
 type remoteName struct {
-	repo      *git2go.Repository
+	repo      middleware.Repository
 	remoteUrl string
 }
 
@@ -38,7 +38,7 @@ func (r remoteName) GetRemoteNameWithUrl() string {
 	return ""
 }
 
-func NewGetRemoteName(repo *git2go.Repository, remoteUrl string) Name {
+func NewGetRemoteName(repo middleware.Repository, remoteUrl string) Name {
 	return remoteName{
 		repo:      repo,
 		remoteUrl: remoteUrl,
diff --git a/git/remote/git_remote_url_data.go b/git/remote/git_remote_url_data.go
index 8a45ed6..d3d0f70 100644
--- a/git/remote/git_remote_url_data.go
+++ b/git/remote/git_remote_url_data.go
@@ -1,7 +1,7 @@
 package remote
 
 import (
-	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 )
 
@@ -10,7 +10,7 @@ type ListRemoteUrl interface {
 }
 
 type listRemoteUrl struct {
-	repo *git2go.Repository
+	repo middleware.Repository
 }
 
 func (u listRemoteUrl) GetAllRemoteUrl() []*string {
@@ -41,6 +41,6 @@ func (u listRemoteUrl) GetAllRemoteUrl() []*string {
 	return remoteURL
 }
 
-func NewRemoteUrlData(repo *git2go.Repository) ListRemoteUrl {
+func NewRemoteUrlData(repo middleware.Repository) ListRemoteUrl {
 	return listRemoteUrl{repo: repo}
 }
diff --git a/git/remote/git_remote_url_data_test.go b/git/remote/git_remote_url_data_test.go
index 60a0860..ae29c6f 100644
--- a/git/remote/git_remote_url_data_test.go
+++ b/git/remote/git_remote_url_data_test.go
@@ -2,18 +2,21 @@ package remote
 
 import (
 	"fmt"
+	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
-	"path/filepath"
 	"testing"
 )
 
 type RemoteUrlDataTestSuite struct {
 	suite.Suite
-	repo          *git2go.Repository
-	noHeadRepo    *git2go.Repository
-	listRemoteUrl ListRemoteUrl
+	repo           middleware.Repository
+	mockController *gomock.Controller
+	mockRepo       *mocks.MockRepository
+	listRemoteUrl  ListRemoteUrl
 }
 
 func TestRemoteUrlDataTestSuite(t *testing.T) {
@@ -25,15 +28,16 @@ func (suite *RemoteUrlDataTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
-	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
 
-	suite.repo = r
-	suite.noHeadRepo = noHeadRepo
-	suite.listRemoteUrl = NewRemoteUrlData(r)
+	suite.repo = middleware.NewRepository(r)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.listRemoteUrl = NewRemoteUrlData(suite.mockRepo)
 }
 
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesArePresent_ShouldReturnRemoteUrlList() {
+	suite.listRemoteUrl = NewRemoteUrlData(suite.repo)
+
 	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
 
 	suite.NotZero(len(urlList))
@@ -49,7 +53,7 @@ func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoIsNil_ShouldRet
 }
 
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoHasNoRemotes_ShouldReturnNil() {
-	suite.listRemoteUrl = NewRemoteUrlData(suite.noHeadRepo)
+	suite.listRemoteUrl = NewRemoteUrlData(suite.mockRepo)
 
 	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
 
@@ -57,9 +61,7 @@ func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoHasNoRemotes_Sh
 }
 
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesAreNil_ShouldReturnNil() {
-	suite.listRemoteUrl = NewRemoteUrlData(&git2go.Repository{
-		Remotes: git2go.RemoteCollection{},
-	})
+	suite.listRemoteUrl = NewRemoteUrlData(suite.mockRepo)
 
 	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
 
diff --git a/git/remote/remote_validation.go b/git/remote/remote_validation.go
index 78f2868..001f74a 100644
--- a/git/remote/remote_validation.go
+++ b/git/remote/remote_validation.go
@@ -3,6 +3,7 @@ package remote
 import (
 	"errors"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 )
 
 type Validation interface {
@@ -10,7 +11,7 @@ type Validation interface {
 }
 
 type validation struct {
-	repo         *git2go.Repository
+	repo         middleware.Repository
 	remoteFields []string
 }
 
@@ -51,14 +52,14 @@ func (v validation) validateRepo() error {
 }
 
 func (v validation) validateRemoteCollection() error {
-	if v.repo.Remotes == (git2go.RemoteCollection{}) {
+	if v.repo.Remotes().Get() == (git2go.RemoteCollection{}) {
 		return errors.New("remote collection is nil")
 	}
 
 	return nil
 }
 
-func NewRemoteValidation(repo *git2go.Repository, remoteFields ...string) Validation {
+func NewRemoteValidation(repo middleware.Repository, remoteFields ...string) Validation {
 	return validation{
 		repo:         repo,
 		remoteFields: remoteFields,
diff --git a/git/remote/remote_validation_test.go b/git/remote/remote_validation_test.go
index b1cf31d..324f13d 100644
--- a/git/remote/remote_validation_test.go
+++ b/git/remote/remote_validation_test.go
@@ -2,7 +2,10 @@ package remote
 
 import (
 	"fmt"
+	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
 	"testing"
@@ -10,7 +13,9 @@ import (
 
 type RemoteValidationTestSuite struct {
 	suite.Suite
-	repo                 *git2go.Repository
+	repo                 middleware.Repository
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
 	remoteFields         []string
 	validateRemoteFields Validation
 }
@@ -26,11 +31,15 @@ func (suite *RemoteValidationTestSuite) SetupTest() {
 	}
 
 	suite.remoteFields = []string{"origin", "origin_1"}
-	suite.repo = r
-	suite.validateRemoteFields = NewRemoteValidation(suite.repo, suite.remoteFields[0], suite.remoteFields[1])
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.repo = middleware.NewRepository(r)
+	suite.validateRemoteFields = NewRemoteValidation(suite.mockRepo, suite.remoteFields[0], suite.remoteFields[1])
 }
 
 func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenAllFieldsAreValid_ShouldReturnNil() {
+	suite.validateRemoteFields = NewRemoteValidation(suite.repo)
+
 	wantErr := suite.validateRemoteFields.ValidateRemoteFields()
 
 	fmt.Println(wantErr)
@@ -48,9 +57,7 @@ func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRepoIsNil_S
 }
 
 func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRemoteCollectionIsNil_ShouldReturnError() {
-	suite.validateRemoteFields = NewRemoteValidation(&git2go.Repository{
-		Remotes: git2go.RemoteCollection{},
-	})
+	suite.validateRemoteFields = NewRemoteValidation(suite.mockRepo)
 	wantErr := suite.validateRemoteFields.ValidateRemoteFields()
 	wantErrorText := "remote collection is nil"
 
diff --git a/init/init_remote.go b/init/init_remote.go
index 0842ecb..d012ef4 100644
--- a/init/init_remote.go
+++ b/init/init_remote.go
@@ -3,6 +3,7 @@ package initialize
 import (
 	"context"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/git/remote"
 )
 
@@ -22,7 +23,8 @@ type Remote struct {
 }
 
 func RemoteObjects(ctx context.Context) Remote {
-	repo := ctx.Value(Repo).(*git2go.Repository)
+	r := ctx.Value(Repo).(*git2go.Repository)
+	repo := middleware.NewRepository(r)
 	remoteName := ctx.Value(RemoteName).(string)
 	remoteUrl := ctx.Value(RemoteUrl).(string)
 
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
index 5beb725..390fd65 100644
--- a/mocks/mock_repository.go
+++ b/mocks/mock_repository.go
@@ -145,6 +145,20 @@ func (mr *MockRepositoryMockRecorder) LookupTree(id interface{}) *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupTree", reflect.TypeOf((*MockRepository)(nil).LookupTree), id)
 }
 
+// Remotes mocks base method.
+func (m *MockRepository) Remotes() middleware.Remotes {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Remotes")
+	ret0, _ := ret[0].(middleware.Remotes)
+	return ret0
+}
+
+// Remotes indicates an expected call of Remotes.
+func (mr *MockRepositoryMockRecorder) Remotes() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Remotes", reflect.TypeOf((*MockRepository)(nil).Remotes))
+}
+
 // Walk mocks base method.
 func (m *MockRepository) Walk() (middleware.RevWalk, error) {
 	m.ctrl.T.Helper()

From aa8e85aad080034a17fd6f2396b8bbbeb4e41a46 Mon Sep 17 00:00:00 2001
From: Neel <neelusenthil1996@gmail.com>
Date: Sat, 7 Aug 2021 21:15:52 +0530
Subject: [PATCH 082/148] revise tests for get remote name api

---
 generate_all_mocks.sh                     |  4 +-
 git/remote/git_remote_remote_name.go      | 20 +++++----
 git/remote/git_remote_remote_name_test.go | 55 +++++++++++++++++------
 mocks/mock_git_remote_list.go             | 49 ++++++++++++++++++++
 mocks/mock_remote_validation.go           | 48 ++++++++++++++++++++
 5 files changed, 152 insertions(+), 24 deletions(-)
 create mode 100644 mocks/mock_git_remote_list.go
 create mode 100644 mocks/mock_remote_validation.go

diff --git a/generate_all_mocks.sh b/generate_all_mocks.sh
index fa0c14a..0c92d8d 100755
--- a/generate_all_mocks.sh
+++ b/generate_all_mocks.sh
@@ -6,4 +6,6 @@ mockgen -source=git/middleware/reference.go -destination=mocks/mock_reference.go
 mockgen -source=git/middleware/index.go -destination=mocks/mock_index.go -package=mocks
 mockgen -source=git/commit/git_list_all_commit_logs.go -destination=mocks/mock_git_list_all_commit_logs.go -package=mocks
 mockgen -source=git/middleware/commit.go -destination=mocks/mock_commit.go -package=mocks
-mockgen -source=git/commit/git_commit_file_history.go -destination=mocks/mock_git_commit_file_history.go -package=mocks
\ No newline at end of file
+mockgen -source=git/commit/git_commit_file_history.go -destination=mocks/mock_git_commit_file_history.go -package=mocks
+mockgen -source=git/remote/remote_validation.go -destination=mocks/mock_remote_validation.go -package=mocks
+mockgen -source=git/remote/git_remote_list.go -destination=mock_git_remote_list.go -package=mocks
\ No newline at end of file
diff --git a/git/remote/git_remote_remote_name.go b/git/remote/git_remote_remote_name.go
index bea1f20..72b14d6 100644
--- a/git/remote/git_remote_remote_name.go
+++ b/git/remote/git_remote_remote_name.go
@@ -10,19 +10,19 @@ type Name interface {
 }
 
 type remoteName struct {
-	repo      middleware.Repository
-	remoteUrl string
+	repo             middleware.Repository
+	remoteUrl        string
+	remoteValidation Validation
+	remoteList       List
 }
 
 func (r remoteName) GetRemoteNameWithUrl() string {
-	repo := r.repo
-
-	if validationErr := NewRemoteValidation(repo).ValidateRemoteFields(); validationErr != nil {
+	if validationErr := r.remoteValidation.ValidateRemoteFields(); validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return ""
 	}
 
-	remoteList := NewRemoteList(r.repo).GetAllRemotes()
+	remoteList := r.remoteList.GetAllRemotes()
 	if remoteList == nil {
 		logger.Log("repo has no remotes", global.StatusError)
 		return ""
@@ -38,9 +38,11 @@ func (r remoteName) GetRemoteNameWithUrl() string {
 	return ""
 }
 
-func NewGetRemoteName(repo middleware.Repository, remoteUrl string) Name {
+func NewGetRemoteName(repo middleware.Repository, remoteUrl string, remoteValidation Validation, remoteList List) Name {
 	return remoteName{
-		repo:      repo,
-		remoteUrl: remoteUrl,
+		repo:             repo,
+		remoteUrl:        remoteUrl,
+		remoteValidation: remoteValidation,
+		remoteList:       remoteList,
 	}
 }
diff --git a/git/remote/git_remote_remote_name_test.go b/git/remote/git_remote_remote_name_test.go
index 8cd4502..051c4de 100644
--- a/git/remote/git_remote_remote_name_test.go
+++ b/git/remote/git_remote_remote_name_test.go
@@ -1,19 +1,28 @@
 package remote
 
 import (
+	"errors"
 	"fmt"
+	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
-	"path/filepath"
 	"testing"
 )
 
 type GetRemoteNameTestSuite struct {
 	suite.Suite
-	getRemoteName Name
-	repo          *git2go.Repository
-	noHeadRepo    *git2go.Repository
+	getRemoteName        Name
+	repo                 middleware.Repository
+	remoteValidation     Validation
+	remoteList           List
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockRemoteValidation *mocks.MockValidation
+	mockRemoteList       *mocks.MockList
+	noHeadRepo           *git2go.Repository
 }
 
 func (suite *GetRemoteNameTestSuite) SetupTest() {
@@ -21,12 +30,20 @@ func (suite *GetRemoteNameTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
-	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
 
-	suite.repo = r
-	suite.noHeadRepo = noHeadRepo
-	suite.getRemoteName = NewGetRemoteName(suite.repo, "https://github.com/neel1996/gitconvex-test.git")
+	suite.repo = middleware.NewRepository(r)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+	suite.remoteList = NewRemoteList(suite.repo)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
+	suite.mockRemoteList = mocks.NewMockList(suite.mockController)
+	suite.getRemoteName = NewGetRemoteName(
+		suite.mockRepo,
+		"https://github.com/neel1996/gitconvex-test.git",
+		suite.mockRemoteValidation,
+		suite.mockRemoteList,
+	)
 }
 
 func TestGetRemoteNameTestSuite(t *testing.T) {
@@ -34,6 +51,13 @@ func TestGetRemoteNameTestSuite(t *testing.T) {
 }
 
 func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnRemoteName_WhenRemoteUrlIsValid() {
+	suite.getRemoteName = NewGetRemoteName(
+		suite.repo,
+		"https://github.com/neel1996/gitconvex-test.git",
+		suite.remoteValidation,
+		suite.remoteList,
+	)
+
 	expectedRemote := "origin"
 
 	actualRemote := suite.getRemoteName.GetRemoteNameWithUrl()
@@ -41,20 +65,23 @@ func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnRemoteName_Wh
 	suite.Equal(expectedRemote, actualRemote)
 }
 
-func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_WhenRepoIsNil() {
+func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_WhenValidationFails() {
 	expectedRemote := ""
-	getRemoteName := NewGetRemoteName(nil, "https://github.com/neel1996/gitconvex-test.git")
 
-	actualRemote := getRemoteName.GetRemoteNameWithUrl()
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(errors.New("VALIDATION_ERROR"))
+
+	actualRemote := suite.getRemoteName.GetRemoteNameWithUrl()
 
 	suite.Equal(expectedRemote, actualRemote)
 }
 
 func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_WhenRepoHasNoRemotes() {
 	expectedRemote := ""
-	getRemoteName := NewGetRemoteName(suite.noHeadRepo, "https://github.com/neel1996/gitconvex-test.git")
 
-	actualRemote := getRemoteName.GetRemoteNameWithUrl()
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return(nil)
+
+	actualRemote := suite.getRemoteName.GetRemoteNameWithUrl()
 
 	suite.Equal(expectedRemote, actualRemote)
 }
diff --git a/mocks/mock_git_remote_list.go b/mocks/mock_git_remote_list.go
new file mode 100644
index 0000000..878dc3d
--- /dev/null
+++ b/mocks/mock_git_remote_list.go
@@ -0,0 +1,49 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/remote/git_remote_list.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	model "github.com/neel1996/gitconvex/graph/model"
+)
+
+// MockList is a mock of List interface.
+type MockList struct {
+	ctrl     *gomock.Controller
+	recorder *MockListMockRecorder
+}
+
+// MockListMockRecorder is the mock recorder for MockList.
+type MockListMockRecorder struct {
+	mock *MockList
+}
+
+// NewMockList creates a new mock instance.
+func NewMockList(ctrl *gomock.Controller) *MockList {
+	mock := &MockList{ctrl: ctrl}
+	mock.recorder = &MockListMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockList) EXPECT() *MockListMockRecorder {
+	return m.recorder
+}
+
+// GetAllRemotes mocks base method.
+func (m *MockList) GetAllRemotes() []*model.RemoteDetails {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetAllRemotes")
+	ret0, _ := ret[0].([]*model.RemoteDetails)
+	return ret0
+}
+
+// GetAllRemotes indicates an expected call of GetAllRemotes.
+func (mr *MockListMockRecorder) GetAllRemotes() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllRemotes", reflect.TypeOf((*MockList)(nil).GetAllRemotes))
+}
diff --git a/mocks/mock_remote_validation.go b/mocks/mock_remote_validation.go
new file mode 100644
index 0000000..1f5cd8b
--- /dev/null
+++ b/mocks/mock_remote_validation.go
@@ -0,0 +1,48 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/remote/remote_validation.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockValidation is a mock of Validation interface.
+type MockValidation struct {
+	ctrl     *gomock.Controller
+	recorder *MockValidationMockRecorder
+}
+
+// MockValidationMockRecorder is the mock recorder for MockValidation.
+type MockValidationMockRecorder struct {
+	mock *MockValidation
+}
+
+// NewMockValidation creates a new mock instance.
+func NewMockValidation(ctrl *gomock.Controller) *MockValidation {
+	mock := &MockValidation{ctrl: ctrl}
+	mock.recorder = &MockValidationMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockValidation) EXPECT() *MockValidationMockRecorder {
+	return m.recorder
+}
+
+// ValidateRemoteFields mocks base method.
+func (m *MockValidation) ValidateRemoteFields() error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ValidateRemoteFields")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// ValidateRemoteFields indicates an expected call of ValidateRemoteFields.
+func (mr *MockValidationMockRecorder) ValidateRemoteFields() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateRemoteFields", reflect.TypeOf((*MockValidation)(nil).ValidateRemoteFields))
+}

From 76d8c52d8dd33b6f1cc033d5ac86ae147fe2188e Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 9 Aug 2021 23:46:55 +0530
Subject: [PATCH 083/148] update test for remote add api with mocks

---
 generate_all_mocks.sh             |   3 +-
 git/remote/git_remote_add.go      |  18 +++--
 git/remote/git_remote_add_test.go |  53 ++++++-------
 go.mod                            |   2 +-
 go.sum                            |  12 +--
 init/init_remote.go               |   6 +-
 mocks/mock_remotes.go             | 122 ++++++++++++++++++++++++++++++
 7 files changed, 167 insertions(+), 49 deletions(-)
 create mode 100644 mocks/mock_remotes.go

diff --git a/generate_all_mocks.sh b/generate_all_mocks.sh
index 0c92d8d..f483479 100755
--- a/generate_all_mocks.sh
+++ b/generate_all_mocks.sh
@@ -8,4 +8,5 @@ mockgen -source=git/commit/git_list_all_commit_logs.go -destination=mocks/mock_g
 mockgen -source=git/middleware/commit.go -destination=mocks/mock_commit.go -package=mocks
 mockgen -source=git/commit/git_commit_file_history.go -destination=mocks/mock_git_commit_file_history.go -package=mocks
 mockgen -source=git/remote/remote_validation.go -destination=mocks/mock_remote_validation.go -package=mocks
-mockgen -source=git/remote/git_remote_list.go -destination=mock_git_remote_list.go -package=mocks
\ No newline at end of file
+mockgen -source=git/remote/git_remote_list.go -destination=mocks/mock_git_remote_list.go -package=mocks
+mockgen -source=git/middleware/remotes.go -destination=mocks/mock_remotes.go -package=mocks
\ No newline at end of file
diff --git a/git/remote/git_remote_add.go b/git/remote/git_remote_add.go
index ebff9f0..212c70e 100644
--- a/git/remote/git_remote_add.go
+++ b/git/remote/git_remote_add.go
@@ -11,9 +11,10 @@ type Add interface {
 }
 
 type addRemote struct {
-	repo       middleware.Repository
-	remoteName string
-	remoteURL  string
+	repo             middleware.Repository
+	remoteName       string
+	remoteURL        string
+	remoteValidation Validation
 }
 
 // NewRemote adds a new remote to the target git repo
@@ -34,7 +35,7 @@ func (a addRemote) NewRemote() error {
 }
 
 func (a addRemote) validateRemoteFields() error {
-	validationErr := NewRemoteValidation(a.repo, a.remoteName, a.remoteURL).ValidateRemoteFields()
+	validationErr := a.remoteValidation.ValidateRemoteFields()
 	if validationErr != nil {
 		return validationErr
 	}
@@ -42,10 +43,11 @@ func (a addRemote) validateRemoteFields() error {
 	return nil
 }
 
-func NewAddRemote(repo middleware.Repository, remoteName string, remoteURL string) Add {
+func NewAddRemote(repo middleware.Repository, remoteName string, remoteURL string, remoteValidation Validation) Add {
 	return addRemote{
-		repo:       repo,
-		remoteName: remoteName,
-		remoteURL:  remoteURL,
+		repo:             repo,
+		remoteName:       remoteName,
+		remoteURL:        remoteURL,
+		remoteValidation: remoteValidation,
 	}
 }
diff --git a/git/remote/git_remote_add_test.go b/git/remote/git_remote_add_test.go
index a24f16a..fcb572c 100644
--- a/git/remote/git_remote_add_test.go
+++ b/git/remote/git_remote_add_test.go
@@ -1,10 +1,13 @@
 package remote
 
 import (
+	"errors"
 	"fmt"
+	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
 	"testing"
@@ -12,10 +15,16 @@ import (
 
 type RemoteAddTestSuite struct {
 	suite.Suite
-	repo       middleware.Repository
-	remoteName string
-	remoteUrl  string
-	addRemote  Add
+	mockController       *gomock.Controller
+	repo                 middleware.Repository
+	remotes              middleware.Remotes
+	mockRepo             *mocks.MockRepository
+	mockRemotes          *mocks.MockRemotes
+	mockRemoteValidation *mocks.MockValidation
+	remoteName           string
+	remoteUrl            string
+	addRemote            Add
+	remoteValidation     Validation
 }
 
 func TestRemoteAddTestSuite(t *testing.T) {
@@ -28,9 +37,15 @@ func (suite *RemoteAddTestSuite) SetupTest() {
 		fmt.Println(err)
 	}
 	suite.repo = middleware.NewRepository(r)
+	suite.remotes = middleware.NewRemotes(r.Remotes)
 	suite.remoteName = "new_origin"
 	suite.remoteUrl = "https://github.com/neel1996/gitconvex-test.git"
-	suite.addRemote = NewAddRemote(suite.repo, suite.remoteName, suite.remoteUrl)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRemotes = mocks.NewMockRemotes(suite.mockController)
+	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
+	suite.remoteValidation = NewRemoteValidation(suite.repo, suite.remoteName, suite.remoteUrl)
+	suite.addRemote = NewAddRemote(suite.mockRepo, suite.remoteName, suite.remoteUrl, suite.mockRemoteValidation)
 }
 
 func (suite *RemoteAddTestSuite) TearDownSuite() {
@@ -42,29 +57,15 @@ func (suite *RemoteAddTestSuite) TearDownSuite() {
 }
 
 func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenNewRemoteIsAdded_ShouldReturnNil() {
-	err := suite.addRemote.NewRemote()
-
-	suite.Nil(err)
-}
-
-func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRepoIsNil_ShouldReturnError() {
-	suite.addRemote = NewAddRemote(nil, suite.remoteName, suite.remoteUrl)
-
-	err := suite.addRemote.NewRemote()
-
-	suite.NotNil(err)
-}
-
-func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteNameIsEmpty_ShouldReturnError() {
-	suite.addRemote = NewAddRemote(suite.repo, "", suite.remoteUrl)
+	suite.addRemote = NewAddRemote(suite.repo, suite.remoteName, suite.remoteUrl, suite.remoteValidation)
 
 	err := suite.addRemote.NewRemote()
 
-	suite.NotNil(err)
+	suite.Nil(err)
 }
 
-func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteUrlIsEmpty_ShouldReturnError() {
-	suite.addRemote = NewAddRemote(suite.repo, suite.remoteName, "")
+func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenValidationFails_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(errors.New("VALIDATION_ERROR"))
 
 	err := suite.addRemote.NewRemote()
 
@@ -72,9 +73,9 @@ func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteUrlIsEmpty_ShouldRet
 }
 
 func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteCreationFails_ShouldReturnError() {
-	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-
-	suite.addRemote = NewAddRemote(middleware.NewRepository(r), "new_origin", "https://github.com/neel1996/gitconvex-test.git")
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().Create(suite.remoteName, suite.remoteUrl).Return(&git2go.Remote{}, errors.New("REMOTE_ERROR"))
 
 	err := suite.addRemote.NewRemote()
 
diff --git a/go.mod b/go.mod
index 1fb13ea..7f7b3b1 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.16
 
 require (
 	github.com/99designs/gqlgen v0.13.0
-	github.com/golang/mock v1.6.0 // indirect
+	github.com/golang/mock v1.6.0
 	github.com/google/uuid v1.1.2
 	github.com/gorilla/mux v1.8.0
 	github.com/libgit2/git2go/v31 v31.4.10
diff --git a/go.sum b/go.sum
index bb54219..f402527 100644
--- a/go.sum
+++ b/go.sum
@@ -8,7 +8,6 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNg
 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
 github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
 github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
-github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -47,19 +46,16 @@ github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047 h1:zCoDWFD5
 github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
 github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
 github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
 github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
-github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
-github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
 github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
@@ -70,7 +66,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
 github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
 github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
 github.com/vektah/gqlparser/v2 v2.1.0 h1:uiKJ+T5HMGGQM2kRKQ8Pxw8+Zq9qhhZhz/lieYvCMns=
@@ -81,7 +76,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k=
 golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -95,13 +89,12 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201204225414-ed752295db88 h1:KmZPnMocC93w341XZp26yTJg8Za7lhb2KhkYmixoeso=
 golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -109,13 +102,10 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
 golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589 h1:rjUrONFu4kLchcZTfp3/96bR8bW8dIa8uz3cR5n0cgM=
 golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
diff --git a/init/init_remote.go b/init/init_remote.go
index d012ef4..68d1f54 100644
--- a/init/init_remote.go
+++ b/init/init_remote.go
@@ -28,11 +28,13 @@ func RemoteObjects(ctx context.Context) Remote {
 	remoteName := ctx.Value(RemoteName).(string)
 	remoteUrl := ctx.Value(RemoteUrl).(string)
 
-	addRemote := remote.NewAddRemote(repo, remoteName, remoteUrl)
+	remoteValidation := remote.NewRemoteValidation(repo, remoteName, remoteUrl)
+
+	addRemote := remote.NewAddRemote(repo, remoteName, remoteUrl, remoteValidation)
 	deleteRemote := remote.NewDeleteRemote(repo, remoteName)
 	editRemote := remote.NewEditRemote(repo, remoteName, remoteUrl)
 	listRemote := remote.NewRemoteList(repo)
-	name := remote.NewGetRemoteName(repo, remoteUrl)
+	name := remote.NewGetRemoteName(repo, remoteUrl, remoteValidation, listRemote)
 	listRemoteURL := remote.NewRemoteUrlData(repo)
 
 	return Remote{
diff --git a/mocks/mock_remotes.go b/mocks/mock_remotes.go
new file mode 100644
index 0000000..292cf21
--- /dev/null
+++ b/mocks/mock_remotes.go
@@ -0,0 +1,122 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/remotes.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockRemotes is a mock of Remotes interface.
+type MockRemotes struct {
+	ctrl     *gomock.Controller
+	recorder *MockRemotesMockRecorder
+}
+
+// MockRemotesMockRecorder is the mock recorder for MockRemotes.
+type MockRemotesMockRecorder struct {
+	mock *MockRemotes
+}
+
+// NewMockRemotes creates a new mock instance.
+func NewMockRemotes(ctrl *gomock.Controller) *MockRemotes {
+	mock := &MockRemotes{ctrl: ctrl}
+	mock.recorder = &MockRemotesMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockRemotes) EXPECT() *MockRemotesMockRecorder {
+	return m.recorder
+}
+
+// Create mocks base method.
+func (m *MockRemotes) Create(arg0, arg1 string) (*git.Remote, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Create", arg0, arg1)
+	ret0, _ := ret[0].(*git.Remote)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Create indicates an expected call of Create.
+func (mr *MockRemotesMockRecorder) Create(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockRemotes)(nil).Create), arg0, arg1)
+}
+
+// Delete mocks base method.
+func (m *MockRemotes) Delete(arg0 string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Delete", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Delete indicates an expected call of Delete.
+func (mr *MockRemotesMockRecorder) Delete(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockRemotes)(nil).Delete), arg0)
+}
+
+// Get mocks base method.
+func (m *MockRemotes) Get() git.RemoteCollection {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Get")
+	ret0, _ := ret[0].(git.RemoteCollection)
+	return ret0
+}
+
+// Get indicates an expected call of Get.
+func (mr *MockRemotesMockRecorder) Get() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockRemotes)(nil).Get))
+}
+
+// List mocks base method.
+func (m *MockRemotes) List() ([]string, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "List")
+	ret0, _ := ret[0].([]string)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// List indicates an expected call of List.
+func (mr *MockRemotesMockRecorder) List() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockRemotes)(nil).List))
+}
+
+// Lookup mocks base method.
+func (m *MockRemotes) Lookup(arg0 string) (*git.Remote, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Lookup", arg0)
+	ret0, _ := ret[0].(*git.Remote)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Lookup indicates an expected call of Lookup.
+func (mr *MockRemotesMockRecorder) Lookup(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lookup", reflect.TypeOf((*MockRemotes)(nil).Lookup), arg0)
+}
+
+// SetUrl mocks base method.
+func (m *MockRemotes) SetUrl(arg0, arg1 string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SetUrl", arg0, arg1)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// SetUrl indicates an expected call of SetUrl.
+func (mr *MockRemotesMockRecorder) SetUrl(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUrl", reflect.TypeOf((*MockRemotes)(nil).SetUrl), arg0, arg1)
+}

From c82eb41b7b677e4fe80bc8519aa08e7168113981 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 10 Aug 2021 00:14:56 +0530
Subject: [PATCH 084/148] revise remote delete api and tests

---
 api/repo_status.go                   |  9 +++++-
 git/remote/git_remote_add_test.go    |  4 ++-
 git/remote/git_remote_delete.go      | 18 ++++++-----
 git/remote/git_remote_delete_test.go | 48 ++++++++++++++++++----------
 init/init_remote.go                  |  2 +-
 5 files changed, 54 insertions(+), 27 deletions(-)

diff --git a/api/repo_status.go b/api/repo_status.go
index 2124eb7..75cb1ef 100644
--- a/api/repo_status.go
+++ b/api/repo_status.go
@@ -12,6 +12,8 @@ import (
 	"strings"
 )
 
+//TODO: This is a temporary function and will be replaced with an clean interface over the course of refactoring
+
 // RepoStatus collects the basic details of the target repo and returns the consolidated result
 func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	logger.Log("Collecting repo status information", global.StatusInfo)
@@ -61,7 +63,12 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	}
 
 	if len(remotes) > 0 && *remotes[0] != "" {
-		remoteNameObject := remote.NewGetRemoteName(repoForRemote, *remotes[0])
+		remoteNameObject := remote.NewGetRemoteName(
+			repoForRemote,
+			*remotes[0],
+			remote.NewRemoteValidation(repoForRemote),
+			remote.NewRemoteList(repoForRemote),
+		)
 		remoteName = remoteNameObject.GetRemoteNameWithUrl()
 		sRemote := strings.Split(*remotes[0], "/")
 		repoName = &sRemote[len(sRemote)-1]
diff --git a/git/remote/git_remote_add_test.go b/git/remote/git_remote_add_test.go
index fcb572c..01e90a4 100644
--- a/git/remote/git_remote_add_test.go
+++ b/git/remote/git_remote_add_test.go
@@ -49,7 +49,9 @@ func (suite *RemoteAddTestSuite) SetupTest() {
 }
 
 func (suite *RemoteAddTestSuite) TearDownSuite() {
-	err := NewDeleteRemote(suite.repo, suite.remoteName).DeleteRemote()
+	suite.remoteValidation = NewRemoteValidation(suite.repo, suite.remoteName)
+
+	err := NewDeleteRemote(suite.repo, suite.remoteName, suite.remoteValidation).DeleteRemote()
 	if err != nil {
 		logger.Log(err.Error(), global.StatusWarning)
 		return
diff --git a/git/remote/git_remote_delete.go b/git/remote/git_remote_delete.go
index a454a1c..7a866b0 100644
--- a/git/remote/git_remote_delete.go
+++ b/git/remote/git_remote_delete.go
@@ -11,13 +11,14 @@ type Delete interface {
 }
 
 type deleteRemote struct {
-	repo       middleware.Repository
-	remoteName string
+	repo             middleware.Repository
+	remoteName       string
+	remoteValidation Validation
 }
 
 // DeleteRemote deletes the remote based on the specified remoteName
 func (d deleteRemote) DeleteRemote() error {
-	validationError := NewRemoteValidation(d.repo, d.remoteName).ValidateRemoteFields()
+	validationError := d.remoteValidation.ValidateRemoteFields()
 	if validationError != nil {
 		return validationError
 	}
@@ -31,8 +32,8 @@ func (d deleteRemote) DeleteRemote() error {
 	return nil
 }
 
-func (d *deleteRemote) deleteSelectedRemote(remoteEntry string) error {
-	err := d.repo.Remotes().Delete(remoteEntry)
+func (d *deleteRemote) deleteSelectedRemote(remoteName string) error {
+	err := d.repo.Remotes().Delete(remoteName)
 	if err != nil {
 		logger.Log(err.Error(), global.StatusError)
 		return err
@@ -42,9 +43,10 @@ func (d *deleteRemote) deleteSelectedRemote(remoteEntry string) error {
 	return nil
 }
 
-func NewDeleteRemote(repo middleware.Repository, remoteName string) Delete {
+func NewDeleteRemote(repo middleware.Repository, remoteName string, remoteValidation Validation) Delete {
 	return deleteRemote{
-		repo:       repo,
-		remoteName: remoteName,
+		repo:             repo,
+		remoteName:       remoteName,
+		remoteValidation: remoteValidation,
 	}
 }
diff --git a/git/remote/git_remote_delete_test.go b/git/remote/git_remote_delete_test.go
index 0d846fe..5835255 100644
--- a/git/remote/git_remote_delete_test.go
+++ b/git/remote/git_remote_delete_test.go
@@ -1,9 +1,12 @@
 package remote
 
 import (
+	"errors"
 	"fmt"
+	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
 	"testing"
@@ -11,9 +14,14 @@ import (
 
 type RemoteDeleteTestSuite struct {
 	suite.Suite
-	repo         middleware.Repository
-	remoteName   string
-	deleteRemote Delete
+	repo                 middleware.Repository
+	remoteName           string
+	deleteRemote         Delete
+	remoteValidation     Validation
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockRemoteValidation *mocks.MockValidation
+	mockRemotes          *mocks.MockRemotes
 }
 
 func TestRemoteDeleteTestSuite(t *testing.T) {
@@ -25,8 +33,11 @@ func (suite *RemoteDeleteTestSuite) SetupSuite() {
 	if err != nil {
 		fmt.Println(err)
 	}
+	suite.repo = middleware.NewRepository(r)
 	suite.remoteName = "new_origin"
-	_ = NewAddRemote(middleware.NewRepository(r), suite.remoteName, "remote://some_url").NewRemote()
+	suite.remoteValidation = NewRemoteValidation(suite.repo, suite.remoteName)
+
+	_ = NewAddRemote(suite.repo, suite.remoteName, "remote://some_url", suite.remoteValidation).NewRemote()
 }
 
 func (suite *RemoteDeleteTestSuite) SetupTest() {
@@ -36,25 +47,28 @@ func (suite *RemoteDeleteTestSuite) SetupTest() {
 	}
 	suite.repo = middleware.NewRepository(r)
 	suite.remoteName = "new_origin"
-	suite.deleteRemote = NewDeleteRemote(suite.repo, suite.remoteName)
-}
-
-func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenNewRemoteIsDeleted_ShouldReturnNoError() {
-	err := suite.deleteRemote.DeleteRemote()
+	suite.remoteValidation = NewRemoteValidation(suite.repo, suite.remoteName)
 
-	suite.Nil(err)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
+	suite.mockRemotes = mocks.NewMockRemotes(suite.mockController)
+	suite.deleteRemote = NewDeleteRemote(suite.mockRepo, suite.remoteName, suite.mockRemoteValidation)
 }
 
-func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRepoIsNil_ShouldReturnError() {
-	suite.deleteRemote = NewDeleteRemote(nil, suite.remoteName)
+func (suite *RemoteDeleteTestSuite) TearDownTest() {
+	suite.mockController.Finish()
+}
 
+func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenNewRemoteIsDeleted_ShouldReturnNoError() {
+	suite.deleteRemote = NewDeleteRemote(suite.repo, suite.remoteName, suite.remoteValidation)
 	err := suite.deleteRemote.DeleteRemote()
 
-	suite.NotNil(err)
+	suite.Nil(err)
 }
 
-func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteNameIsEmpty_ShouldReturnError() {
-	suite.deleteRemote = NewDeleteRemote(suite.repo, "")
+func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteValidationFails_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(errors.New("VALIDATION_ERROR"))
 
 	err := suite.deleteRemote.DeleteRemote()
 
@@ -62,7 +76,9 @@ func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteNameIsEmpty_Sh
 }
 
 func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteDeletionFails_ShouldReturnError() {
-	suite.deleteRemote = NewDeleteRemote(suite.repo, "new_origin")
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().Delete(suite.remoteName).Return(errors.New("DELETION_FAILS"))
 
 	err := suite.deleteRemote.DeleteRemote()
 
diff --git a/init/init_remote.go b/init/init_remote.go
index 68d1f54..287301b 100644
--- a/init/init_remote.go
+++ b/init/init_remote.go
@@ -31,7 +31,7 @@ func RemoteObjects(ctx context.Context) Remote {
 	remoteValidation := remote.NewRemoteValidation(repo, remoteName, remoteUrl)
 
 	addRemote := remote.NewAddRemote(repo, remoteName, remoteUrl, remoteValidation)
-	deleteRemote := remote.NewDeleteRemote(repo, remoteName)
+	deleteRemote := remote.NewDeleteRemote(repo, remoteName, remoteValidation)
 	editRemote := remote.NewEditRemote(repo, remoteName, remoteUrl)
 	listRemote := remote.NewRemoteList(repo)
 	name := remote.NewGetRemoteName(repo, remoteUrl, remoteValidation, listRemote)

From ad978909853e3e57883794c00972e1b196884a2e Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 12 Aug 2021 21:52:24 +0530
Subject: [PATCH 085/148] update remote validation function to accept remote
 fields as function params

---
 git/remote/remote_validation.go      | 10 +++++-----
 git/remote/remote_validation_test.go | 21 ++++++++++++++-------
 mocks/mock_remote_validation.go      | 12 ++++++++----
 3 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/git/remote/remote_validation.go b/git/remote/remote_validation.go
index 001f74a..539a924 100644
--- a/git/remote/remote_validation.go
+++ b/git/remote/remote_validation.go
@@ -7,7 +7,7 @@ import (
 )
 
 type Validation interface {
-	ValidateRemoteFields() error
+	ValidateRemoteFields(remoteFields ...string) error
 }
 
 type validation struct {
@@ -15,7 +15,8 @@ type validation struct {
 	remoteFields []string
 }
 
-func (v validation) ValidateRemoteFields() error {
+func (v validation) ValidateRemoteFields(remoteFields ...string) error {
+	v.remoteFields = remoteFields
 	validateRepoErr := v.validateRepo()
 	if validateRepoErr != nil {
 		return validateRepoErr
@@ -59,9 +60,8 @@ func (v validation) validateRemoteCollection() error {
 	return nil
 }
 
-func NewRemoteValidation(repo middleware.Repository, remoteFields ...string) Validation {
+func NewRemoteValidation(repo middleware.Repository) Validation {
 	return validation{
-		repo:         repo,
-		remoteFields: remoteFields,
+		repo: repo,
 	}
 }
diff --git a/git/remote/remote_validation_test.go b/git/remote/remote_validation_test.go
index 324f13d..23b0c42 100644
--- a/git/remote/remote_validation_test.go
+++ b/git/remote/remote_validation_test.go
@@ -16,6 +16,7 @@ type RemoteValidationTestSuite struct {
 	repo                 middleware.Repository
 	mockController       *gomock.Controller
 	mockRepo             *mocks.MockRepository
+	mockRemotes          *mocks.MockRemotes
 	remoteFields         []string
 	validateRemoteFields Validation
 }
@@ -34,21 +35,21 @@ func (suite *RemoteValidationTestSuite) SetupTest() {
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
 	suite.repo = middleware.NewRepository(r)
-	suite.validateRemoteFields = NewRemoteValidation(suite.mockRepo, suite.remoteFields[0], suite.remoteFields[1])
+	suite.mockRemotes = mocks.NewMockRemotes(suite.mockController)
+	suite.validateRemoteFields = NewRemoteValidation(suite.mockRepo)
 }
 
 func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenAllFieldsAreValid_ShouldReturnNil() {
 	suite.validateRemoteFields = NewRemoteValidation(suite.repo)
 
-	wantErr := suite.validateRemoteFields.ValidateRemoteFields()
-
-	fmt.Println(wantErr)
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields(suite.remoteFields[0], suite.remoteFields[1])
 
 	suite.Nil(wantErr)
 }
 
 func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRepoIsNil_ShouldReturnError() {
 	suite.validateRemoteFields = NewRemoteValidation(nil)
+
 	wantErr := suite.validateRemoteFields.ValidateRemoteFields()
 	wantErrorText := "repo is nil"
 
@@ -57,7 +58,9 @@ func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRepoIsNil_S
 }
 
 func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRemoteCollectionIsNil_ShouldReturnError() {
-	suite.validateRemoteFields = NewRemoteValidation(suite.mockRepo)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().Get().Return(git2go.RemoteCollection{})
+
 	wantErr := suite.validateRemoteFields.ValidateRemoteFields()
 	wantErrorText := "remote collection is nil"
 
@@ -66,8 +69,12 @@ func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRemoteColle
 }
 
 func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRemoteFieldsAreEmpty_ShouldReturnError() {
-	suite.validateRemoteFields = NewRemoteValidation(suite.repo, "", "")
-	wantErr := suite.validateRemoteFields.ValidateRemoteFields()
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().Get().DoAndReturn(func() git2go.RemoteCollection {
+		return suite.repo.Remotes().Get()
+	})
+
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields("", "")
 	wantErrorText := "one or more remote fields are empty"
 
 	suite.NotNil(wantErr)
diff --git a/mocks/mock_remote_validation.go b/mocks/mock_remote_validation.go
index 1f5cd8b..d5042c4 100644
--- a/mocks/mock_remote_validation.go
+++ b/mocks/mock_remote_validation.go
@@ -34,15 +34,19 @@ func (m *MockValidation) EXPECT() *MockValidationMockRecorder {
 }
 
 // ValidateRemoteFields mocks base method.
-func (m *MockValidation) ValidateRemoteFields() error {
+func (m *MockValidation) ValidateRemoteFields(remoteFields ...string) error {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ValidateRemoteFields")
+	varargs := []interface{}{}
+	for _, a := range remoteFields {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ValidateRemoteFields", varargs...)
 	ret0, _ := ret[0].(error)
 	return ret0
 }
 
 // ValidateRemoteFields indicates an expected call of ValidateRemoteFields.
-func (mr *MockValidationMockRecorder) ValidateRemoteFields() *gomock.Call {
+func (mr *MockValidationMockRecorder) ValidateRemoteFields(remoteFields ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateRemoteFields", reflect.TypeOf((*MockValidation)(nil).ValidateRemoteFields))
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateRemoteFields", reflect.TypeOf((*MockValidation)(nil).ValidateRemoteFields), remoteFields...)
 }

From 101f630b09ba4b130f7bc02e71c0527f311dc490 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 12 Aug 2021 22:20:52 +0530
Subject: [PATCH 086/148] revise edit remote struct items and add more tests

---
 git/remote/git_remote_edit.go      | 23 +++++----
 git/remote/git_remote_edit_test.go | 82 ++++++++++++++++++++----------
 init/init_remote.go                |  6 +--
 3 files changed, 71 insertions(+), 40 deletions(-)

diff --git a/git/remote/git_remote_edit.go b/git/remote/git_remote_edit.go
index 15a8130..874dd14 100644
--- a/git/remote/git_remote_edit.go
+++ b/git/remote/git_remote_edit.go
@@ -12,22 +12,23 @@ type Edit interface {
 }
 
 type editRemote struct {
-	repo       middleware.Repository
-	remoteName string
-	remoteURL  string
+	repo             middleware.Repository
+	remoteName       string
+	remoteURL        string
+	remoteValidation Validation
+	remoteList       List
 }
 
 func (e editRemote) EditRemote() error {
 	repo := e.repo
 
-	validationErr := NewRemoteValidation(e.repo, e.remoteName, e.remoteURL).ValidateRemoteFields()
+	validationErr := e.remoteValidation.ValidateRemoteFields(e.remoteName, e.remoteURL)
 	if validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return validationErr
 	}
 
 	_, listErr := repo.Remotes().List()
-
 	if listErr != nil {
 		logger.Log(listErr.Error(), global.StatusError)
 		return listErr
@@ -50,7 +51,7 @@ func (e editRemote) EditRemote() error {
 
 func (e editRemote) isRemotePresentInRepo() error {
 	var err error
-	remoteList := NewRemoteList(e.repo).GetAllRemotes()
+	remoteList := e.remoteList.GetAllRemotes()
 
 	if remoteList == nil {
 		err = errors.New("no remotes are present in the repo")
@@ -68,10 +69,12 @@ func (e editRemote) isRemotePresentInRepo() error {
 	return err
 }
 
-func NewEditRemote(repo middleware.Repository, remoteName string, remoteURL string) Edit {
+func NewEditRemote(repo middleware.Repository, remoteName string, remoteURL string, remoteValidation Validation, remoteList List) Edit {
 	return editRemote{
-		repo:       repo,
-		remoteName: remoteName,
-		remoteURL:  remoteURL,
+		repo:             repo,
+		remoteName:       remoteName,
+		remoteURL:        remoteURL,
+		remoteValidation: remoteValidation,
+		remoteList:       remoteList,
 	}
 }
diff --git a/git/remote/git_remote_edit_test.go b/git/remote/git_remote_edit_test.go
index 3ee97ad..360bc11 100644
--- a/git/remote/git_remote_edit_test.go
+++ b/git/remote/git_remote_edit_test.go
@@ -1,10 +1,12 @@
 package remote
 
 import (
+	"errors"
 	"fmt"
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
@@ -13,13 +15,17 @@ import (
 
 type RemoteEditTestSuite struct {
 	suite.Suite
-	repo           middleware.Repository
-	mockController *gomock.Controller
-	mockRepo       *mocks.MockRepository
-	remoteName     string
-	remoteUrl      string
-	validation     Validation
-	editRemote     Edit
+	repo                 middleware.Repository
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockRemoteValidation *mocks.MockValidation
+	mockRemoteList       *mocks.MockList
+	mockRemotes          *mocks.MockRemotes
+	remoteName           string
+	remoteUrl            string
+	remoteValidation     Validation
+	remoteList           List
+	editRemote           Edit
 }
 
 func TestRemoteEditTestSuite(t *testing.T) {
@@ -35,61 +41,83 @@ func (suite *RemoteEditTestSuite) SetupTest() {
 	suite.repo = middleware.NewRepository(r)
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRemotes = mocks.NewMockRemotes(suite.mockController)
+	suite.mockRemoteList = mocks.NewMockList(suite.mockController)
+	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
+
 	suite.remoteName = "origin"
 	suite.remoteUrl = "https://github.com/neel1996/gitconvex-test.git"
-	suite.editRemote = NewEditRemote(suite.mockRepo, suite.remoteName, suite.remoteUrl)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+	suite.remoteList = NewRemoteList(suite.repo)
+	suite.editRemote = NewEditRemote(
+		suite.mockRepo,
+		suite.remoteName,
+		suite.remoteUrl,
+		suite.mockRemoteValidation,
+		suite.mockRemoteList,
+	)
 }
 
 func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsEdited_ShouldReturnNil() {
-	suite.editRemote = NewEditRemote(suite.repo, suite.remoteName, suite.remoteUrl)
+	suite.editRemote = NewEditRemote(suite.repo, suite.remoteName, suite.remoteUrl, suite.remoteValidation, suite.remoteList)
 
 	wantErr := suite.editRemote.EditRemote()
 
 	suite.Nil(wantErr)
 }
 
-func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoIsNil_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(nil, suite.remoteName, suite.remoteUrl)
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteValidationFails_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(errors.New("VALIDATION_ERR"))
 
 	wantErr := suite.editRemote.EditRemote()
 
 	suite.NotNil(wantErr)
 }
 
-func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteCollectionIsNil_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(suite.mockRepo, suite.remoteName, suite.remoteUrl)
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteListReturnsError_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().List().Return(nil, errors.New("LIST_ERROR"))
 
 	wantErr := suite.editRemote.EditRemote()
 
 	suite.NotNil(wantErr)
 }
 
-func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteNameIsEmpty_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(suite.mockRepo, "", suite.remoteUrl)
-
-	wantErr := suite.editRemote.EditRemote()
-
-	suite.NotNil(wantErr)
-}
-
-func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteUrlIsEmpty_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(suite.mockRepo, suite.remoteName, "")
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsNotPresent_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().List().Return([]string{}, nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return(nil)
 
 	wantErr := suite.editRemote.EditRemote()
 
 	suite.NotNil(wantErr)
 }
 
-func (suite *RemoteEditTestSuite) TestEditRemote_WhenRepoHasNoRemotes_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(suite.mockRepo, suite.remoteName, suite.remoteUrl)
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsNotPresentInRepo_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().List().Return([]string{}, nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return([]*model.RemoteDetails{{
+		RemoteName: "INVALID",
+	}})
 
 	wantErr := suite.editRemote.EditRemote()
 
 	suite.NotNil(wantErr)
 }
 
-func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsNotPresent_ShouldReturnError() {
-	suite.editRemote = NewEditRemote(suite.mockRepo, "no_exists_remote", suite.remoteUrl)
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteSetUrlFails_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().List().Return([]string{}, nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return([]*model.RemoteDetails{{
+		RemoteName: suite.remoteName,
+		RemoteURL:  suite.remoteUrl,
+	}})
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().SetUrl(suite.remoteName, suite.remoteUrl).Return(errors.New("SET_URL_ERROR"))
 
 	wantErr := suite.editRemote.EditRemote()
 
diff --git a/init/init_remote.go b/init/init_remote.go
index 287301b..c236d30 100644
--- a/init/init_remote.go
+++ b/init/init_remote.go
@@ -28,12 +28,12 @@ func RemoteObjects(ctx context.Context) Remote {
 	remoteName := ctx.Value(RemoteName).(string)
 	remoteUrl := ctx.Value(RemoteUrl).(string)
 
-	remoteValidation := remote.NewRemoteValidation(repo, remoteName, remoteUrl)
+	remoteValidation := remote.NewRemoteValidation(repo)
 
+	listRemote := remote.NewRemoteList(repo)
 	addRemote := remote.NewAddRemote(repo, remoteName, remoteUrl, remoteValidation)
 	deleteRemote := remote.NewDeleteRemote(repo, remoteName, remoteValidation)
-	editRemote := remote.NewEditRemote(repo, remoteName, remoteUrl)
-	listRemote := remote.NewRemoteList(repo)
+	editRemote := remote.NewEditRemote(repo, remoteName, remoteUrl, remoteValidation, listRemote)
 	name := remote.NewGetRemoteName(repo, remoteUrl, remoteValidation, listRemote)
 	listRemoteURL := remote.NewRemoteUrlData(repo)
 

From 9b9c0b35f943f34a521befb215f423ffdf887a4c Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 12 Aug 2021 22:22:03 +0530
Subject: [PATCH 087/148] update remote validation in add remote api

---
 git/remote/git_remote_add.go      | 11 +----------
 git/remote/git_remote_add_test.go |  8 ++++----
 2 files changed, 5 insertions(+), 14 deletions(-)

diff --git a/git/remote/git_remote_add.go b/git/remote/git_remote_add.go
index 212c70e..76906da 100644
--- a/git/remote/git_remote_add.go
+++ b/git/remote/git_remote_add.go
@@ -19,7 +19,7 @@ type addRemote struct {
 
 // NewRemote adds a new remote to the target git repo
 func (a addRemote) NewRemote() error {
-	if validationErr := a.validateRemoteFields(); validationErr != nil {
+	if validationErr := a.remoteValidation.ValidateRemoteFields(a.remoteName, a.remoteURL); validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return validationErr
 	}
@@ -34,15 +34,6 @@ func (a addRemote) NewRemote() error {
 	return nil
 }
 
-func (a addRemote) validateRemoteFields() error {
-	validationErr := a.remoteValidation.ValidateRemoteFields()
-	if validationErr != nil {
-		return validationErr
-	}
-
-	return nil
-}
-
 func NewAddRemote(repo middleware.Repository, remoteName string, remoteURL string, remoteValidation Validation) Add {
 	return addRemote{
 		repo:             repo,
diff --git a/git/remote/git_remote_add_test.go b/git/remote/git_remote_add_test.go
index 01e90a4..5465a3d 100644
--- a/git/remote/git_remote_add_test.go
+++ b/git/remote/git_remote_add_test.go
@@ -44,12 +44,12 @@ func (suite *RemoteAddTestSuite) SetupTest() {
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
 	suite.mockRemotes = mocks.NewMockRemotes(suite.mockController)
 	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
-	suite.remoteValidation = NewRemoteValidation(suite.repo, suite.remoteName, suite.remoteUrl)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
 	suite.addRemote = NewAddRemote(suite.mockRepo, suite.remoteName, suite.remoteUrl, suite.mockRemoteValidation)
 }
 
 func (suite *RemoteAddTestSuite) TearDownSuite() {
-	suite.remoteValidation = NewRemoteValidation(suite.repo, suite.remoteName)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
 
 	err := NewDeleteRemote(suite.repo, suite.remoteName, suite.remoteValidation).DeleteRemote()
 	if err != nil {
@@ -67,7 +67,7 @@ func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenNewRemoteIsAdded_ShouldRet
 }
 
 func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenValidationFails_ShouldReturnError() {
-	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(errors.New("VALIDATION_ERROR"))
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(errors.New("VALIDATION_ERROR"))
 
 	err := suite.addRemote.NewRemote()
 
@@ -75,7 +75,7 @@ func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenValidationFails_ShouldRetu
 }
 
 func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteCreationFails_ShouldReturnError() {
-	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(nil)
 	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
 	suite.mockRemotes.EXPECT().Create(suite.remoteName, suite.remoteUrl).Return(&git2go.Remote{}, errors.New("REMOTE_ERROR"))
 

From 882ba69205087652c12d0cfc9c11d84aa5efdef2 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 12 Aug 2021 22:23:00 +0530
Subject: [PATCH 088/148] update remote validation in delete remote api

---
 git/remote/git_remote_delete.go      | 2 +-
 git/remote/git_remote_delete_test.go | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/git/remote/git_remote_delete.go b/git/remote/git_remote_delete.go
index 7a866b0..8067229 100644
--- a/git/remote/git_remote_delete.go
+++ b/git/remote/git_remote_delete.go
@@ -18,7 +18,7 @@ type deleteRemote struct {
 
 // DeleteRemote deletes the remote based on the specified remoteName
 func (d deleteRemote) DeleteRemote() error {
-	validationError := d.remoteValidation.ValidateRemoteFields()
+	validationError := d.remoteValidation.ValidateRemoteFields(d.remoteName)
 	if validationError != nil {
 		return validationError
 	}
diff --git a/git/remote/git_remote_delete_test.go b/git/remote/git_remote_delete_test.go
index 5835255..d1d9a04 100644
--- a/git/remote/git_remote_delete_test.go
+++ b/git/remote/git_remote_delete_test.go
@@ -35,7 +35,7 @@ func (suite *RemoteDeleteTestSuite) SetupSuite() {
 	}
 	suite.repo = middleware.NewRepository(r)
 	suite.remoteName = "new_origin"
-	suite.remoteValidation = NewRemoteValidation(suite.repo, suite.remoteName)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
 
 	_ = NewAddRemote(suite.repo, suite.remoteName, "remote://some_url", suite.remoteValidation).NewRemote()
 }
@@ -47,7 +47,7 @@ func (suite *RemoteDeleteTestSuite) SetupTest() {
 	}
 	suite.repo = middleware.NewRepository(r)
 	suite.remoteName = "new_origin"
-	suite.remoteValidation = NewRemoteValidation(suite.repo, suite.remoteName)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
 
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
@@ -68,7 +68,7 @@ func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenNewRemoteIsDeleted_S
 }
 
 func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteValidationFails_ShouldReturnError() {
-	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(errors.New("VALIDATION_ERROR"))
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName).Return(errors.New("VALIDATION_ERROR"))
 
 	err := suite.deleteRemote.DeleteRemote()
 
@@ -76,7 +76,7 @@ func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteValidationFail
 }
 
 func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteDeletionFails_ShouldReturnError() {
-	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName).Return(nil)
 	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
 	suite.mockRemotes.EXPECT().Delete(suite.remoteName).Return(errors.New("DELETION_FAILS"))
 

From 2c3c87301bd40613b661c5d7b3e15f8cf3f087b1 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 21 Aug 2021 19:56:47 +0530
Subject: [PATCH 089/148] improve unit test coverage for remote url data

---
 git/remote/git_remote_url_data.go      | 18 ++++++++------
 git/remote/git_remote_url_data_test.go | 33 ++++++++++++++++++--------
 2 files changed, 34 insertions(+), 17 deletions(-)

diff --git a/git/remote/git_remote_url_data.go b/git/remote/git_remote_url_data.go
index d3d0f70..53faf8b 100644
--- a/git/remote/git_remote_url_data.go
+++ b/git/remote/git_remote_url_data.go
@@ -10,20 +10,20 @@ type ListRemoteUrl interface {
 }
 
 type listRemoteUrl struct {
-	repo middleware.Repository
+	repo             middleware.Repository
+	remoteValidation Validation
+	remoteList       List
 }
 
 func (u listRemoteUrl) GetAllRemoteUrl() []*string {
 	var remoteURL []*string
 
-	repo := u.repo
-
-	if validationErr := NewRemoteValidation(repo).ValidateRemoteFields(); validationErr != nil {
+	if validationErr := u.remoteValidation.ValidateRemoteFields(); validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return nil
 	}
 
-	remoteList := NewRemoteList(u.repo).GetAllRemotes()
+	remoteList := u.remoteList.GetAllRemotes()
 	if remoteList == nil {
 		logger.Log("repo has no remotes", global.StatusError)
 		return nil
@@ -41,6 +41,10 @@ func (u listRemoteUrl) GetAllRemoteUrl() []*string {
 	return remoteURL
 }
 
-func NewRemoteUrlData(repo middleware.Repository) ListRemoteUrl {
-	return listRemoteUrl{repo: repo}
+func NewRemoteUrlData(repo middleware.Repository, remoteValidation Validation, remoteList List) ListRemoteUrl {
+	return listRemoteUrl{
+		repo:             repo,
+		remoteValidation: remoteValidation,
+		remoteList:       remoteList,
+	}
 }
diff --git a/git/remote/git_remote_url_data_test.go b/git/remote/git_remote_url_data_test.go
index ae29c6f..7848522 100644
--- a/git/remote/git_remote_url_data_test.go
+++ b/git/remote/git_remote_url_data_test.go
@@ -1,10 +1,12 @@
 package remote
 
 import (
+	"errors"
 	"fmt"
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
@@ -13,10 +15,14 @@ import (
 
 type RemoteUrlDataTestSuite struct {
 	suite.Suite
-	repo           middleware.Repository
-	mockController *gomock.Controller
-	mockRepo       *mocks.MockRepository
-	listRemoteUrl  ListRemoteUrl
+	repo                 middleware.Repository
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockRemoteList       *mocks.MockList
+	mockRemoteValidation *mocks.MockValidation
+	remoteValidation     Validation
+	remoteList           List
+	listRemoteUrl        ListRemoteUrl
 }
 
 func TestRemoteUrlDataTestSuite(t *testing.T) {
@@ -30,13 +36,18 @@ func (suite *RemoteUrlDataTestSuite) SetupTest() {
 	}
 
 	suite.repo = middleware.NewRepository(r)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+	suite.remoteList = NewRemoteList(suite.repo, suite.remoteValidation)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.listRemoteUrl = NewRemoteUrlData(suite.mockRepo)
+	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
+	suite.mockRemoteList = mocks.NewMockList(suite.mockController)
+	suite.listRemoteUrl = NewRemoteUrlData(suite.mockRepo, suite.mockRemoteValidation, suite.mockRemoteList)
 }
 
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesArePresent_ShouldReturnRemoteUrlList() {
-	suite.listRemoteUrl = NewRemoteUrlData(suite.repo)
+	suite.listRemoteUrl = NewRemoteUrlData(suite.repo, suite.remoteValidation, suite.remoteList)
 
 	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
 
@@ -44,8 +55,8 @@ func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesArePresent_S
 	suite.Equal("https://github.com/neel1996/gitconvex-test.git", *urlList[0])
 }
 
-func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoIsNil_ShouldReturnNil() {
-	suite.listRemoteUrl = NewRemoteUrlData(nil)
+func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemoteValidationFails_ShouldReturnNil() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(errors.New("VALIDATION_ERR"))
 
 	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
 
@@ -53,7 +64,8 @@ func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoIsNil_ShouldRet
 }
 
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoHasNoRemotes_ShouldReturnNil() {
-	suite.listRemoteUrl = NewRemoteUrlData(suite.mockRepo)
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return(nil)
 
 	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
 
@@ -61,7 +73,8 @@ func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoHasNoRemotes_Sh
 }
 
 func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesAreNil_ShouldReturnNil() {
-	suite.listRemoteUrl = NewRemoteUrlData(suite.mockRepo)
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return([]*model.RemoteDetails{})
 
 	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
 

From d5938da8ad40652aa7df8b473f617834cc2941c5 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 21 Aug 2021 20:21:45 +0530
Subject: [PATCH 090/148] add additional tests for remote list api

---
 git/remote/git_remote_list.go      |  9 +++----
 git/remote/git_remote_list_test.go | 38 +++++++++++++++++++++++-------
 2 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/git/remote/git_remote_list.go b/git/remote/git_remote_list.go
index 1567ba9..979b61a 100644
--- a/git/remote/git_remote_list.go
+++ b/git/remote/git_remote_list.go
@@ -12,14 +12,15 @@ type List interface {
 }
 
 type listRemotes struct {
-	repo middleware.Repository
+	repo             middleware.Repository
+	remoteValidation Validation
 }
 
 func (l listRemotes) GetAllRemotes() []*model.RemoteDetails {
 	var remoteList []*model.RemoteDetails
 	repo := l.repo
 
-	if validationErr := NewRemoteValidation(repo).ValidateRemoteFields(); validationErr != nil {
+	if validationErr := l.remoteValidation.ValidateRemoteFields(); validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return nil
 	}
@@ -54,6 +55,6 @@ func (l listRemotes) GetAllRemotes() []*model.RemoteDetails {
 	return remoteList
 }
 
-func NewRemoteList(repo middleware.Repository) List {
-	return listRemotes{repo: repo}
+func NewRemoteList(repo middleware.Repository, remoteValidation Validation) List {
+	return listRemotes{repo: repo, remoteValidation: remoteValidation}
 }
diff --git a/git/remote/git_remote_list_test.go b/git/remote/git_remote_list_test.go
index e41a78c..e1f2929 100644
--- a/git/remote/git_remote_list_test.go
+++ b/git/remote/git_remote_list_test.go
@@ -1,6 +1,7 @@
 package remote
 
 import (
+	"errors"
 	"fmt"
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
@@ -14,10 +15,13 @@ import (
 
 type ListRemoteTestSuite struct {
 	suite.Suite
-	repo           middleware.Repository
-	mockController *gomock.Controller
-	mockRepo       *mocks.MockRepository
-	listRemote     List
+	repo                 middleware.Repository
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockRemoteValidation *mocks.MockValidation
+	mockRemotes          *mocks.MockRemotes
+	listRemote           List
+	remoteValidation     Validation
 }
 
 func (suite *ListRemoteTestSuite) SetupTest() {
@@ -28,8 +32,11 @@ func (suite *ListRemoteTestSuite) SetupTest() {
 
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
 	suite.repo = middleware.NewRepository(r)
-	suite.listRemote = NewRemoteList(suite.repo)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+	suite.mockRemotes = mocks.NewMockRemotes(suite.mockController)
+	suite.listRemote = NewRemoteList(suite.mockRepo, suite.mockRemoteValidation)
 }
 
 func TestListRemoteTestSuite(t *testing.T) {
@@ -37,6 +44,8 @@ func TestListRemoteTestSuite(t *testing.T) {
 }
 
 func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsValid_ShouldReturnAllRemotes() {
+	suite.listRemote = NewRemoteList(suite.repo, suite.remoteValidation)
+
 	expectedRemotes := []*model.RemoteDetails{{
 		RemoteName: "origin",
 		RemoteURL:  "https://github.com/neel1996/gitconvex-test.git",
@@ -49,8 +58,8 @@ func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsValid_ShouldReturn
 	suite.Equal(expectedRemotes[0].RemoteURL, remoteList[0].RemoteURL)
 }
 
-func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsNil_ShouldReturnNil() {
-	suite.listRemote = NewRemoteList(nil)
+func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRemoteValidationFails_ShouldReturnNil() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(errors.New("VALIDATION_ERROR"))
 
 	remoteList := suite.listRemote.GetAllRemotes()
 
@@ -58,7 +67,20 @@ func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsNil_ShouldReturnNi
 }
 
 func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoHasNoRemotes_ShouldReturnNil() {
-	suite.listRemote = NewRemoteList(suite.mockRepo)
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().List().Return([]string{}, errors.New("LIST_ERROR"))
+
+	remoteList := suite.listRemote.GetAllRemotes()
+
+	suite.Nil(remoteList)
+}
+
+func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRemoteLookupFails_ShouldReturnNil() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes).MaxTimes(2)
+	suite.mockRemotes.EXPECT().List().Return([]string{"REMOTE"}, nil)
+	suite.mockRemotes.EXPECT().Lookup("REMOTE").Return(&git2go.Remote{}, errors.New("LOOKUP_ERROR"))
 
 	remoteList := suite.listRemote.GetAllRemotes()
 

From 4e0fcd6100449763986c564f58055c921ff310a8 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 21 Aug 2021 20:32:22 +0530
Subject: [PATCH 091/148] improve unit test coverage with mocks

---
 git/remote/git_remote_edit_test.go        |  2 +-
 git/remote/git_remote_remote_name_test.go | 14 +++++++++++++-
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/git/remote/git_remote_edit_test.go b/git/remote/git_remote_edit_test.go
index 360bc11..6b4a101 100644
--- a/git/remote/git_remote_edit_test.go
+++ b/git/remote/git_remote_edit_test.go
@@ -48,7 +48,7 @@ func (suite *RemoteEditTestSuite) SetupTest() {
 	suite.remoteName = "origin"
 	suite.remoteUrl = "https://github.com/neel1996/gitconvex-test.git"
 	suite.remoteValidation = NewRemoteValidation(suite.repo)
-	suite.remoteList = NewRemoteList(suite.repo)
+	suite.remoteList = NewRemoteList(suite.repo, suite.remoteValidation)
 	suite.editRemote = NewEditRemote(
 		suite.mockRepo,
 		suite.remoteName,
diff --git a/git/remote/git_remote_remote_name_test.go b/git/remote/git_remote_remote_name_test.go
index 051c4de..8d37f43 100644
--- a/git/remote/git_remote_remote_name_test.go
+++ b/git/remote/git_remote_remote_name_test.go
@@ -6,6 +6,7 @@ import (
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
@@ -33,7 +34,7 @@ func (suite *GetRemoteNameTestSuite) SetupTest() {
 
 	suite.repo = middleware.NewRepository(r)
 	suite.remoteValidation = NewRemoteValidation(suite.repo)
-	suite.remoteList = NewRemoteList(suite.repo)
+	suite.remoteList = NewRemoteList(suite.repo, suite.remoteValidation)
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
 	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
@@ -85,3 +86,14 @@ func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_W
 
 	suite.Equal(expectedRemote, actualRemote)
 }
+
+func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_WhenRemoteURLIsNotPresentInRepo() {
+	expectedRemote := ""
+
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return([]*model.RemoteDetails{})
+
+	actualRemote := suite.getRemoteName.GetRemoteNameWithUrl()
+
+	suite.Equal(expectedRemote, actualRemote)
+}

From 5a6b2aa96e0f573fdb384453d83a8b6491a32a32 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 21 Aug 2021 20:38:21 +0530
Subject: [PATCH 092/148] update remote init and repo status functions to match
 new remote apis

---
 api/repo_status.go  | 8 +++++---
 init/init_remote.go | 4 ++--
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/api/repo_status.go b/api/repo_status.go
index 75cb1ef..148e306 100644
--- a/api/repo_status.go
+++ b/api/repo_status.go
@@ -53,7 +53,9 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 
 	repoForRemote := middleware.NewRepository(repo)
 
-	remoteUrlList := remote.NewRemoteUrlData(repoForRemote)
+	remoteValidation := remote.NewRemoteValidation(repoForRemote)
+	remoteList := remote.NewRemoteList(repoForRemote, remoteValidation)
+	remoteUrlList := remote.NewRemoteUrlData(repoForRemote, remoteValidation, remoteList)
 	listRemoteUrl := remote.Operation{ListRemoteUrl: remoteUrlList}
 
 	remotes, remoteErr := listRemoteUrl.GitGetAllRemoteUrl()
@@ -66,8 +68,8 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 		remoteNameObject := remote.NewGetRemoteName(
 			repoForRemote,
 			*remotes[0],
-			remote.NewRemoteValidation(repoForRemote),
-			remote.NewRemoteList(repoForRemote),
+			remoteValidation,
+			remoteList,
 		)
 		remoteName = remoteNameObject.GetRemoteNameWithUrl()
 		sRemote := strings.Split(*remotes[0], "/")
diff --git a/init/init_remote.go b/init/init_remote.go
index c236d30..4c7592f 100644
--- a/init/init_remote.go
+++ b/init/init_remote.go
@@ -30,12 +30,12 @@ func RemoteObjects(ctx context.Context) Remote {
 
 	remoteValidation := remote.NewRemoteValidation(repo)
 
-	listRemote := remote.NewRemoteList(repo)
+	listRemote := remote.NewRemoteList(repo, remoteValidation)
 	addRemote := remote.NewAddRemote(repo, remoteName, remoteUrl, remoteValidation)
 	deleteRemote := remote.NewDeleteRemote(repo, remoteName, remoteValidation)
 	editRemote := remote.NewEditRemote(repo, remoteName, remoteUrl, remoteValidation, listRemote)
 	name := remote.NewGetRemoteName(repo, remoteUrl, remoteValidation, listRemote)
-	listRemoteURL := remote.NewRemoteUrlData(repo)
+	listRemoteURL := remote.NewRemoteUrlData(repo, remoteValidation, listRemote)
 
 	return Remote{
 		AddRemote:     addRemote,

From bce75934868331f348773d3a016a47ef94a97151 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 22 Aug 2021 19:47:58 +0530
Subject: [PATCH 093/148] move remote api specific mocks to remote directory

---
 git/remote/git_remote_add_test.go                   |  9 +++++----
 git/remote/git_remote_delete_test.go                |  9 +++++----
 git/remote/git_remote_edit_test.go                  | 13 +++++++------
 git/remote/git_remote_list_test.go                  |  9 +++++----
 git/remote/git_remote_remote_name_test.go           |  9 +++++----
 git/remote/git_remote_url_data_test.go              |  9 +++++----
 {mocks => git/remote/mocks}/mock_git_remote_list.go |  0
 .../remote/mocks}/mock_remote_validation.go         |  0
 {mocks => git/remote/mocks}/mock_remotes.go         |  0
 git/remote/remote_validation_test.go                |  5 +++--
 10 files changed, 35 insertions(+), 28 deletions(-)
 rename {mocks => git/remote/mocks}/mock_git_remote_list.go (100%)
 rename {mocks => git/remote/mocks}/mock_remote_validation.go (100%)
 rename {mocks => git/remote/mocks}/mock_remotes.go (100%)

diff --git a/git/remote/git_remote_add_test.go b/git/remote/git_remote_add_test.go
index 5465a3d..dbdd2ec 100644
--- a/git/remote/git_remote_add_test.go
+++ b/git/remote/git_remote_add_test.go
@@ -6,6 +6,7 @@ import (
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
@@ -19,8 +20,8 @@ type RemoteAddTestSuite struct {
 	repo                 middleware.Repository
 	remotes              middleware.Remotes
 	mockRepo             *mocks.MockRepository
-	mockRemotes          *mocks.MockRemotes
-	mockRemoteValidation *mocks.MockValidation
+	mockRemotes          *remoteMocks.MockRemotes
+	mockRemoteValidation *remoteMocks.MockValidation
 	remoteName           string
 	remoteUrl            string
 	addRemote            Add
@@ -42,8 +43,8 @@ func (suite *RemoteAddTestSuite) SetupTest() {
 	suite.remoteUrl = "https://github.com/neel1996/gitconvex-test.git"
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.mockRemotes = mocks.NewMockRemotes(suite.mockController)
-	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
+	suite.mockRemotes = remoteMocks.NewMockRemotes(suite.mockController)
+	suite.mockRemoteValidation = remoteMocks.NewMockValidation(suite.mockController)
 	suite.remoteValidation = NewRemoteValidation(suite.repo)
 	suite.addRemote = NewAddRemote(suite.mockRepo, suite.remoteName, suite.remoteUrl, suite.mockRemoteValidation)
 }
diff --git a/git/remote/git_remote_delete_test.go b/git/remote/git_remote_delete_test.go
index d1d9a04..4787ce3 100644
--- a/git/remote/git_remote_delete_test.go
+++ b/git/remote/git_remote_delete_test.go
@@ -6,6 +6,7 @@ import (
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
@@ -20,8 +21,8 @@ type RemoteDeleteTestSuite struct {
 	remoteValidation     Validation
 	mockController       *gomock.Controller
 	mockRepo             *mocks.MockRepository
-	mockRemoteValidation *mocks.MockValidation
-	mockRemotes          *mocks.MockRemotes
+	mockRemoteValidation *remoteMocks.MockValidation
+	mockRemotes          *remoteMocks.MockRemotes
 }
 
 func TestRemoteDeleteTestSuite(t *testing.T) {
@@ -51,8 +52,8 @@ func (suite *RemoteDeleteTestSuite) SetupTest() {
 
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
-	suite.mockRemotes = mocks.NewMockRemotes(suite.mockController)
+	suite.mockRemoteValidation = remoteMocks.NewMockValidation(suite.mockController)
+	suite.mockRemotes = remoteMocks.NewMockRemotes(suite.mockController)
 	suite.deleteRemote = NewDeleteRemote(suite.mockRepo, suite.remoteName, suite.mockRemoteValidation)
 }
 
diff --git a/git/remote/git_remote_edit_test.go b/git/remote/git_remote_edit_test.go
index 6b4a101..af7e50a 100644
--- a/git/remote/git_remote_edit_test.go
+++ b/git/remote/git_remote_edit_test.go
@@ -6,6 +6,7 @@ import (
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
@@ -18,9 +19,9 @@ type RemoteEditTestSuite struct {
 	repo                 middleware.Repository
 	mockController       *gomock.Controller
 	mockRepo             *mocks.MockRepository
-	mockRemoteValidation *mocks.MockValidation
-	mockRemoteList       *mocks.MockList
-	mockRemotes          *mocks.MockRemotes
+	mockRemoteValidation *remoteMocks.MockValidation
+	mockRemoteList       *remoteMocks.MockList
+	mockRemotes          *remoteMocks.MockRemotes
 	remoteName           string
 	remoteUrl            string
 	remoteValidation     Validation
@@ -41,9 +42,9 @@ func (suite *RemoteEditTestSuite) SetupTest() {
 	suite.repo = middleware.NewRepository(r)
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.mockRemotes = mocks.NewMockRemotes(suite.mockController)
-	suite.mockRemoteList = mocks.NewMockList(suite.mockController)
-	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
+	suite.mockRemotes = remoteMocks.NewMockRemotes(suite.mockController)
+	suite.mockRemoteList = remoteMocks.NewMockList(suite.mockController)
+	suite.mockRemoteValidation = remoteMocks.NewMockValidation(suite.mockController)
 
 	suite.remoteName = "origin"
 	suite.remoteUrl = "https://github.com/neel1996/gitconvex-test.git"
diff --git a/git/remote/git_remote_list_test.go b/git/remote/git_remote_list_test.go
index e1f2929..b7175ee 100644
--- a/git/remote/git_remote_list_test.go
+++ b/git/remote/git_remote_list_test.go
@@ -6,6 +6,7 @@ import (
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
@@ -18,8 +19,8 @@ type ListRemoteTestSuite struct {
 	repo                 middleware.Repository
 	mockController       *gomock.Controller
 	mockRepo             *mocks.MockRepository
-	mockRemoteValidation *mocks.MockValidation
-	mockRemotes          *mocks.MockRemotes
+	mockRemoteValidation *remoteMocks.MockValidation
+	mockRemotes          *remoteMocks.MockRemotes
 	listRemote           List
 	remoteValidation     Validation
 }
@@ -32,10 +33,10 @@ func (suite *ListRemoteTestSuite) SetupTest() {
 
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
+	suite.mockRemoteValidation = remoteMocks.NewMockValidation(suite.mockController)
 	suite.repo = middleware.NewRepository(r)
 	suite.remoteValidation = NewRemoteValidation(suite.repo)
-	suite.mockRemotes = mocks.NewMockRemotes(suite.mockController)
+	suite.mockRemotes = remoteMocks.NewMockRemotes(suite.mockController)
 	suite.listRemote = NewRemoteList(suite.mockRepo, suite.mockRemoteValidation)
 }
 
diff --git a/git/remote/git_remote_remote_name_test.go b/git/remote/git_remote_remote_name_test.go
index 8d37f43..6940ec7 100644
--- a/git/remote/git_remote_remote_name_test.go
+++ b/git/remote/git_remote_remote_name_test.go
@@ -6,6 +6,7 @@ import (
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
@@ -21,8 +22,8 @@ type GetRemoteNameTestSuite struct {
 	remoteList           List
 	mockController       *gomock.Controller
 	mockRepo             *mocks.MockRepository
-	mockRemoteValidation *mocks.MockValidation
-	mockRemoteList       *mocks.MockList
+	mockRemoteValidation *remoteMocks.MockValidation
+	mockRemoteList       *remoteMocks.MockList
 	noHeadRepo           *git2go.Repository
 }
 
@@ -37,8 +38,8 @@ func (suite *GetRemoteNameTestSuite) SetupTest() {
 	suite.remoteList = NewRemoteList(suite.repo, suite.remoteValidation)
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
-	suite.mockRemoteList = mocks.NewMockList(suite.mockController)
+	suite.mockRemoteValidation = remoteMocks.NewMockValidation(suite.mockController)
+	suite.mockRemoteList = remoteMocks.NewMockList(suite.mockController)
 	suite.getRemoteName = NewGetRemoteName(
 		suite.mockRepo,
 		"https://github.com/neel1996/gitconvex-test.git",
diff --git a/git/remote/git_remote_url_data_test.go b/git/remote/git_remote_url_data_test.go
index 7848522..aac5746 100644
--- a/git/remote/git_remote_url_data_test.go
+++ b/git/remote/git_remote_url_data_test.go
@@ -6,6 +6,7 @@ import (
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
@@ -18,8 +19,8 @@ type RemoteUrlDataTestSuite struct {
 	repo                 middleware.Repository
 	mockController       *gomock.Controller
 	mockRepo             *mocks.MockRepository
-	mockRemoteList       *mocks.MockList
-	mockRemoteValidation *mocks.MockValidation
+	mockRemoteList       *remoteMocks.MockList
+	mockRemoteValidation *remoteMocks.MockValidation
 	remoteValidation     Validation
 	remoteList           List
 	listRemoteUrl        ListRemoteUrl
@@ -41,8 +42,8 @@ func (suite *RemoteUrlDataTestSuite) SetupTest() {
 	suite.remoteValidation = NewRemoteValidation(suite.repo)
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.mockRemoteValidation = mocks.NewMockValidation(suite.mockController)
-	suite.mockRemoteList = mocks.NewMockList(suite.mockController)
+	suite.mockRemoteValidation = remoteMocks.NewMockValidation(suite.mockController)
+	suite.mockRemoteList = remoteMocks.NewMockList(suite.mockController)
 	suite.listRemoteUrl = NewRemoteUrlData(suite.mockRepo, suite.mockRemoteValidation, suite.mockRemoteList)
 }
 
diff --git a/mocks/mock_git_remote_list.go b/git/remote/mocks/mock_git_remote_list.go
similarity index 100%
rename from mocks/mock_git_remote_list.go
rename to git/remote/mocks/mock_git_remote_list.go
diff --git a/mocks/mock_remote_validation.go b/git/remote/mocks/mock_remote_validation.go
similarity index 100%
rename from mocks/mock_remote_validation.go
rename to git/remote/mocks/mock_remote_validation.go
diff --git a/mocks/mock_remotes.go b/git/remote/mocks/mock_remotes.go
similarity index 100%
rename from mocks/mock_remotes.go
rename to git/remote/mocks/mock_remotes.go
diff --git a/git/remote/remote_validation_test.go b/git/remote/remote_validation_test.go
index 23b0c42..733cc16 100644
--- a/git/remote/remote_validation_test.go
+++ b/git/remote/remote_validation_test.go
@@ -5,6 +5,7 @@ import (
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
@@ -16,7 +17,7 @@ type RemoteValidationTestSuite struct {
 	repo                 middleware.Repository
 	mockController       *gomock.Controller
 	mockRepo             *mocks.MockRepository
-	mockRemotes          *mocks.MockRemotes
+	mockRemotes          *remoteMocks.MockRemotes
 	remoteFields         []string
 	validateRemoteFields Validation
 }
@@ -35,7 +36,7 @@ func (suite *RemoteValidationTestSuite) SetupTest() {
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
 	suite.repo = middleware.NewRepository(r)
-	suite.mockRemotes = mocks.NewMockRemotes(suite.mockController)
+	suite.mockRemotes = remoteMocks.NewMockRemotes(suite.mockController)
 	suite.validateRemoteFields = NewRemoteValidation(suite.mockRepo)
 }
 

From 0ca2ff76a394da5cd6d142f8fceb70c39845e7a1 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 22 Aug 2021 19:50:48 +0530
Subject: [PATCH 094/148] move commit api mocks to commit folder

---
 git/commit/git_commit_file_history_test.go               | 5 +++--
 git/commit/git_commit_log_mapper_test.go                 | 5 +++--
 git/commit/git_commit_log_search_test.go                 | 9 +++++----
 git/commit/git_total_commits_test.go                     | 5 +++--
 {mocks => git/commit/mocks}/mock_commit.go               | 0
 .../commit/mocks}/mock_git_commit_file_history.go        | 0
 .../commit/mocks}/mock_git_list_all_commit_logs.go       | 0
 7 files changed, 14 insertions(+), 10 deletions(-)
 rename {mocks => git/commit/mocks}/mock_commit.go (100%)
 rename {mocks => git/commit/mocks}/mock_git_commit_file_history.go (100%)
 rename {mocks => git/commit/mocks}/mock_git_list_all_commit_logs.go (100%)

diff --git a/git/commit/git_commit_file_history_test.go b/git/commit/git_commit_file_history_test.go
index 98298d8..3387f81 100644
--- a/git/commit/git_commit_file_history_test.go
+++ b/git/commit/git_commit_file_history_test.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	commitMocks "github.com/neel1996/gitconvex/git/commit/mocks"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
@@ -17,7 +18,7 @@ type FileHistoryTestSuite struct {
 	mockController *gomock.Controller
 	repo           middleware.Repository
 	mockRepo       *mocks.MockRepository
-	mockCommit     *mocks.MockCommit
+	mockCommit     *commitMocks.MockCommit
 	fileHistory    FileHistory
 }
 
@@ -34,7 +35,7 @@ func (suite *FileHistoryTestSuite) SetupTest() {
 	suite.mockController = gomock.NewController(suite.T())
 	suite.repo = middleware.NewRepository(r)
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
+	suite.mockCommit = commitMocks.NewMockCommit(suite.mockController)
 	suite.fileHistory = NewFileHistory(suite.mockRepo)
 }
 
diff --git a/git/commit/git_commit_log_mapper_test.go b/git/commit/git_commit_log_mapper_test.go
index 86ad41d..eeb2c9c 100644
--- a/git/commit/git_commit_log_mapper_test.go
+++ b/git/commit/git_commit_log_mapper_test.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	commitMocks "github.com/neel1996/gitconvex/git/commit/mocks"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
@@ -19,7 +20,7 @@ type CommitLogMapperTestSuite struct {
 	repo            middleware.Repository
 	mockRepo        *mocks.MockRepository
 	fileHistory     FileHistory
-	mockFileHistory *mocks.MockFileHistory
+	mockFileHistory *commitMocks.MockFileHistory
 	commits         []git2go.Commit
 	mapper          Mapper
 }
@@ -42,7 +43,7 @@ func (suite *CommitLogMapperTestSuite) SetupTest() {
 	suite.fileHistory = NewFileHistory(suite.repo)
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.mockFileHistory = mocks.NewMockFileHistory(suite.mockController)
+	suite.mockFileHistory = commitMocks.NewMockFileHistory(suite.mockController)
 
 	suite.mapper = NewMapper(suite.mockFileHistory)
 }
diff --git a/git/commit/git_commit_log_search_test.go b/git/commit/git_commit_log_search_test.go
index e43fd1c..721bd45 100644
--- a/git/commit/git_commit_log_search_test.go
+++ b/git/commit/git_commit_log_search_test.go
@@ -6,6 +6,7 @@ import (
 	"github.com/golang/mock/gomock"
 	git "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/constants"
+	commitMocks "github.com/neel1996/gitconvex/git/commit/mocks"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/neel1996/gitconvex/mocks"
@@ -19,8 +20,8 @@ type SearchLogsTestSuite struct {
 	suite.Suite
 	mockController  *gomock.Controller
 	mockRepo        *mocks.MockRepository
-	mockListLogs    *mocks.MockListAllLogs
-	mockFileHistory *mocks.MockFileHistory
+	mockListLogs    *commitMocks.MockListAllLogs
+	mockFileHistory *commitMocks.MockFileHistory
 	listAllLogs     ListAllLogs
 	mapper          Mapper
 	searchLogs      SearchLogs
@@ -42,8 +43,8 @@ func (suite *SearchLogsTestSuite) SetupTest() {
 	suite.mockController = gomock.NewController(suite.T())
 
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.mockListLogs = mocks.NewMockListAllLogs(suite.mockController)
-	suite.mockFileHistory = mocks.NewMockFileHistory(suite.mockController)
+	suite.mockListLogs = commitMocks.NewMockListAllLogs(suite.mockController)
+	suite.mockFileHistory = commitMocks.NewMockFileHistory(suite.mockController)
 
 	suite.mapper = NewMapper(suite.mockFileHistory)
 	suite.searchLogs = NewSearchLogs(suite.mockRepo, suite.mockListLogs, suite.mapper)
diff --git a/git/commit/git_total_commits_test.go b/git/commit/git_total_commits_test.go
index 20965ce..02df43e 100644
--- a/git/commit/git_total_commits_test.go
+++ b/git/commit/git_total_commits_test.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	commitMocks "github.com/neel1996/gitconvex/git/commit/mocks"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
@@ -21,7 +22,7 @@ type TotalCommitsTestSuite struct {
 	mockRepo          *mocks.MockRepository
 	mockWalker        *mocks.MockRevWalk
 	noHeadRepo        *git2go.Repository
-	mockAllCommitLogs *mocks.MockListAllLogs
+	mockAllCommitLogs *commitMocks.MockListAllLogs
 }
 
 func TestTotalCommitsTestSuite(t *testing.T) {
@@ -42,7 +43,7 @@ func (suite *TotalCommitsTestSuite) SetupTest() {
 	suite.noHeadRepo = noHeadRepo
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
 	suite.mockWalker = mocks.NewMockRevWalk(suite.mockController)
-	suite.mockAllCommitLogs = mocks.NewMockListAllLogs(suite.mockController)
+	suite.mockAllCommitLogs = commitMocks.NewMockListAllLogs(suite.mockController)
 	suite.total = NewTotalCommits(suite.mockAllCommitLogs)
 }
 
diff --git a/mocks/mock_commit.go b/git/commit/mocks/mock_commit.go
similarity index 100%
rename from mocks/mock_commit.go
rename to git/commit/mocks/mock_commit.go
diff --git a/mocks/mock_git_commit_file_history.go b/git/commit/mocks/mock_git_commit_file_history.go
similarity index 100%
rename from mocks/mock_git_commit_file_history.go
rename to git/commit/mocks/mock_git_commit_file_history.go
diff --git a/mocks/mock_git_list_all_commit_logs.go b/git/commit/mocks/mock_git_list_all_commit_logs.go
similarity index 100%
rename from mocks/mock_git_list_all_commit_logs.go
rename to git/commit/mocks/mock_git_list_all_commit_logs.go

From e01ecdc6e4b1eb7a867d0ce6227af07c7a8c0d40 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 22 Aug 2021 19:57:21 +0530
Subject: [PATCH 095/148] update mock generator script with new paths

---
 generate_all_mocks.sh | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/generate_all_mocks.sh b/generate_all_mocks.sh
index f483479..9a8fc3a 100755
--- a/generate_all_mocks.sh
+++ b/generate_all_mocks.sh
@@ -1,12 +1,17 @@
 #!/bin/bash
 
+# Middleware mocks
 mockgen -source=git/middleware/repository.go -destination=mocks/mock_repository.go -package=mocks
 mockgen -source=git/middleware/walk.go -destination=mocks/mock_walk.go -package=mocks
 mockgen -source=git/middleware/reference.go -destination=mocks/mock_reference.go -package=mocks
 mockgen -source=git/middleware/index.go -destination=mocks/mock_index.go -package=mocks
-mockgen -source=git/commit/git_list_all_commit_logs.go -destination=mocks/mock_git_list_all_commit_logs.go -package=mocks
-mockgen -source=git/middleware/commit.go -destination=mocks/mock_commit.go -package=mocks
-mockgen -source=git/commit/git_commit_file_history.go -destination=mocks/mock_git_commit_file_history.go -package=mocks
-mockgen -source=git/remote/remote_validation.go -destination=mocks/mock_remote_validation.go -package=mocks
-mockgen -source=git/remote/git_remote_list.go -destination=mocks/mock_git_remote_list.go -package=mocks
-mockgen -source=git/middleware/remotes.go -destination=mocks/mock_remotes.go -package=mocks
\ No newline at end of file
+
+# Commit mocks
+mockgen -source=git/commit/git_list_all_commit_logs.go -destination=git/commit/mocks/mock_git_list_all_commit_logs.go -package=mocks
+mockgen -source=git/middleware/commit.go -destination=git/commit/mocks/mock_commit.go -package=mocks
+mockgen -source=git/commit/git_commit_file_history.go -destination=git/commit/mocks/mock_git_commit_file_history.go -package=mocks
+
+# Remote mocks
+mockgen -source=git/remote/remote_validation.go -destination=git/remote/mocks/mock_remote_validation.go -package=mocks
+mockgen -source=git/remote/git_remote_list.go -destination=git/remote/mocks/mock_git_remote_list.go -package=mocks
+mockgen -source=git/middleware/remotes.go -destination=git/remote/mocks/mock_remotes.go -package=mocks
\ No newline at end of file

From afdd562e801c3615b35532f1c0cccd6d26e43290 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 22 Aug 2021 20:10:15 +0530
Subject: [PATCH 096/148] update stage names in github actions yaml

---
 .github/workflows/go-collab.yml | 8 ++++----
 .github/workflows/go.yml        | 8 ++++----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index 3ea5599..0c7c01f 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -14,7 +14,7 @@ jobs:
           brew install libssh2
           brew install libgit2
 
-  gitconvex-integration-test:
+  gitconvex-test:
     name: Gitconvex server test
     runs-on: ubuntu-latest
     env:
@@ -48,7 +48,7 @@ jobs:
 
   gitconvex-build:
     needs:
-      - gitconvex-integration-test
+      - gitconvex-test
       - libgit2-setup-test
 
     name: Gitconvex Build
@@ -77,7 +77,7 @@ jobs:
   gitconvex-mock-integration:
     needs:
       - libgit2-setup-test
-      - gitconvex-integration-test
+      - gitconvex-test
       - gitconvex-build
 
     name: Mocking Gitconvex Unified Repo Integration
@@ -104,7 +104,7 @@ jobs:
         run: |
           go get -v -t -d ./...
 
-      - name: Integration checkup
+      - name: Test deployment prep to integrated repo
         run: |
           export TARGET_BRANCH=${{ secrets.TARGET_BRANCH }}
           git clone https://github.com/neel1996/gitconvex-server.git $HOME/gitconvex-server
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 055dc0a..1a1a9ce 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -14,7 +14,7 @@ jobs:
           brew install libssh2
           brew install libgit2
 
-  gitconvex-integration-test:
+  gitconvex-test:
     name: Gitconvex server test
     runs-on: ubuntu-latest
     env:
@@ -48,7 +48,7 @@ jobs:
 
   gitconvex-build:
     needs:
-      - gitconvex-integration-test
+      - gitconvex-test
       - libgit2-setup-test
 
     name: Gitconvex Build
@@ -77,7 +77,7 @@ jobs:
   gitconvex-bundle:
     needs:
       - libgit2-setup-test
-      - gitconvex-integration-test
+      - gitconvex-test
       - gitconvex-build
 
     name: Gitconvex Unified Repo Integration
@@ -104,7 +104,7 @@ jobs:
         run: |
           go get -v -t -d ./...
 
-      - name: Integration checkup
+      - name: Deploy to integrated repo
         run: |
           export TARGET_BRANCH=${{ secrets.TARGET_BRANCH }}
           git clone https://github.com/neel1996/gitconvex-server.git $HOME/gitconvex-server

From 3fb76fbd19976571c6f6801dd79f7c1705526d33 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 22 Aug 2021 20:16:55 +0530
Subject: [PATCH 097/148] fix build failure by updating libgit2 cellar path

---
 .github/workflows/go-collab.yml | 18 +++++++++---------
 .github/workflows/go.yml        | 18 +++++++++---------
 2 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index 0c7c01f..a1a9ce1 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -12,13 +12,13 @@ jobs:
       - name: Install libssh2 and libgit2
         run: |
           brew install libssh2
-          brew install libgit2
+          brew install libgit2@1.1.1
 
   gitconvex-test:
     name: Gitconvex server test
     runs-on: ubuntu-latest
     env:
-      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
+      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
       GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/gitconvex-test
       GITCONVEX_DEFAULT_PATH: /usr/local/gitconvex
 
@@ -26,7 +26,7 @@ jobs:
       - name: Install libgit2 from Homebrew
         run: |
           brew install libssh2
-          brew install libgit2
+          brew install libgit2@1.1.1
 
       - name: Set up Go 1.x
         uses: actions/setup-go@v2
@@ -39,8 +39,8 @@ jobs:
 
       - name: Run Go Test
         run: |
-          sudo cp /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/lib* /usr/lib
-          export PATH="/home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/:$PATH"
+          sudo cp /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/lib* /usr/lib
+          export PATH="/home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/:$PATH"
           git config --global user.name "${{ secrets.ACTION_USER_NAME }}" && git config --global user.email "${{ secrets.ACTION_USER_EMAIL }}"
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
@@ -54,13 +54,13 @@ jobs:
     name: Gitconvex Build
     runs-on: ubuntu-latest
     env:
-      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
+      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
 
     steps:
       - name: Install libgit2 from Homebrew
         run: |
           brew install libssh2
-          brew install libgit2
+          brew install libgit2@1.1.1
 
       - name: Set up Go 1.x
         uses: actions/setup-go@v2
@@ -83,13 +83,13 @@ jobs:
     name: Mocking Gitconvex Unified Repo Integration
     runs-on: ubuntu-latest
     env:
-      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
+      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
 
     steps:
       - name: Install libgit2 from Homebrew
         run: |
           brew install libssh2
-          brew install libgit2
+          brew install libgit2@1.1.1
 
       - name: Set up Go 1.x
         uses: actions/setup-go@v2
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 1a1a9ce..0d2abc5 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -12,13 +12,13 @@ jobs:
       - name: Install libssh2 and libgit2
         run: |
           brew install libssh2
-          brew install libgit2
+          brew install libgit2@1.1.1
 
   gitconvex-test:
     name: Gitconvex server test
     runs-on: ubuntu-latest
     env:
-      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
+      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
       GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/gitconvex-test
       GITCONVEX_DEFAULT_PATH: /usr/local/gitconvex
 
@@ -26,7 +26,7 @@ jobs:
       - name: Install libgit2 from Homebrew
         run: |
           brew install libssh2
-          brew install libgit2
+          brew install libgit2@1.1.1
 
       - name: Set up Go 1.x
         uses: actions/setup-go@v2
@@ -39,8 +39,8 @@ jobs:
 
       - name: Run Go Test
         run: |
-          sudo cp /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/lib* /usr/lib
-          export PATH="/home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/:$PATH"
+          sudo cp /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/lib* /usr/lib
+          export PATH="/home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/:$PATH"
           git config --global user.name "${{ secrets.ACTION_USER_NAME }}" && git config --global user.email "${{ secrets.ACTION_USER_EMAIL }}"
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
@@ -54,13 +54,13 @@ jobs:
     name: Gitconvex Build
     runs-on: ubuntu-latest
     env:
-      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
+      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
 
     steps:
       - name: Install libgit2 from Homebrew
         run: |
           brew install libssh2
-          brew install libgit2
+          brew install libgit2@1.1.1
 
       - name: Set up Go 1.x
         uses: actions/setup-go@v2
@@ -83,13 +83,13 @@ jobs:
     name: Gitconvex Unified Repo Integration
     runs-on: ubuntu-latest
     env:
-      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
+      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
 
     steps:
       - name: Install libgit2 from Homebrew
         run: |
           brew install libssh2
-          brew install libgit2
+          brew install libgit2@1.1.1
 
       - name: Set up Go 1.x
         uses: actions/setup-go@v2

From d4babf6ff18bd701b4885fc451c24841052cf5c1 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 22 Aug 2021 20:28:14 +0530
Subject: [PATCH 098/148] remove incorrect version suffix from brew install

---
 .github/workflows/go-collab.yml | 8 ++++----
 .github/workflows/go.yml        | 8 ++++----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index a1a9ce1..bec6870 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -12,7 +12,7 @@ jobs:
       - name: Install libssh2 and libgit2
         run: |
           brew install libssh2
-          brew install libgit2@1.1.1
+          brew install libgit2
 
   gitconvex-test:
     name: Gitconvex server test
@@ -26,7 +26,7 @@ jobs:
       - name: Install libgit2 from Homebrew
         run: |
           brew install libssh2
-          brew install libgit2@1.1.1
+          brew install libgit2
 
       - name: Set up Go 1.x
         uses: actions/setup-go@v2
@@ -60,7 +60,7 @@ jobs:
       - name: Install libgit2 from Homebrew
         run: |
           brew install libssh2
-          brew install libgit2@1.1.1
+          brew install libgit2
 
       - name: Set up Go 1.x
         uses: actions/setup-go@v2
@@ -89,7 +89,7 @@ jobs:
       - name: Install libgit2 from Homebrew
         run: |
           brew install libssh2
-          brew install libgit2@1.1.1
+          brew install libgit2
 
       - name: Set up Go 1.x
         uses: actions/setup-go@v2
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 0d2abc5..3bef90f 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -12,7 +12,7 @@ jobs:
       - name: Install libssh2 and libgit2
         run: |
           brew install libssh2
-          brew install libgit2@1.1.1
+          brew install libgit2
 
   gitconvex-test:
     name: Gitconvex server test
@@ -26,7 +26,7 @@ jobs:
       - name: Install libgit2 from Homebrew
         run: |
           brew install libssh2
-          brew install libgit2@1.1.1
+          brew install libgit2
 
       - name: Set up Go 1.x
         uses: actions/setup-go@v2
@@ -60,7 +60,7 @@ jobs:
       - name: Install libgit2 from Homebrew
         run: |
           brew install libssh2
-          brew install libgit2@1.1.1
+          brew install libgit2
 
       - name: Set up Go 1.x
         uses: actions/setup-go@v2
@@ -89,7 +89,7 @@ jobs:
       - name: Install libgit2 from Homebrew
         run: |
           brew install libssh2
-          brew install libgit2@1.1.1
+          brew install libgit2
 
       - name: Set up Go 1.x
         uses: actions/setup-go@v2

From 60653e5150fd3638cb5e9f54da650943f991d9db Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 24 Aug 2021 20:20:11 +0530
Subject: [PATCH 099/148] update unit tests for branch validation and add api
 specific errors

---
 git/branch/branch_validation.go      | 13 +++++--------
 git/branch/branch_validation_test.go | 29 +++++++++++++---------------
 git/branch/errors.go                 | 16 +++++++++++++++
 3 files changed, 34 insertions(+), 24 deletions(-)
 create mode 100644 git/branch/errors.go

diff --git a/git/branch/branch_validation.go b/git/branch/branch_validation.go
index 5bc9c00..e0d78e8 100644
--- a/git/branch/branch_validation.go
+++ b/git/branch/branch_validation.go
@@ -1,8 +1,7 @@
 package branch
 
 import (
-	"errors"
-	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 )
 
 type Validation interface {
@@ -10,27 +9,25 @@ type Validation interface {
 }
 
 type validateBranch struct {
-	repo       *git2go.Repository
+	repo       middleware.Repository
 	branchName []string
 }
 
 func (v validateBranch) ValidateBranchFields() error {
 	if v.repo == nil {
-		err := "repo is nil"
-		return errors.New(err)
+		return NilRepoError
 	}
 
 	for _, branchName := range v.branchName {
 		if branchName == "" {
-			err := "branch name is empty"
-			return errors.New(err)
+			return EmptyBranchNameError
 		}
 	}
 
 	return nil
 }
 
-func NewBranchFieldsValidation(repo *git2go.Repository, branchName ...string) Validation {
+func NewBranchFieldsValidation(repo middleware.Repository, branchName ...string) Validation {
 	return validateBranch{
 		repo:       repo,
 		branchName: branchName,
diff --git a/git/branch/branch_validation_test.go b/git/branch/branch_validation_test.go
index 15d1d0f..1bbb6e9 100644
--- a/git/branch/branch_validation_test.go
+++ b/git/branch/branch_validation_test.go
@@ -1,18 +1,18 @@
 package branch
 
 import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
+	"github.com/golang/mock/gomock"
+	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
-	"os"
 	"testing"
 )
 
 type BranchFieldValidationTestSuite struct {
 	suite.Suite
-	repo        *git2go.Repository
-	branchNames []string
-	validation  Validation
+	mockController *gomock.Controller
+	mockRepo       *mocks.MockRepository
+	branchNames    []string
+	validation     Validation
 }
 
 func TestBranchFieldValidationTestSuite(t *testing.T) {
@@ -20,14 +20,10 @@ func TestBranchFieldValidationTestSuite(t *testing.T) {
 }
 
 func (suite *BranchFieldValidationTestSuite) SetupTest() {
-	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	if err != nil {
-		fmt.Println(err)
-	}
-
-	suite.repo = r
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
 	suite.branchNames = []string{"test_branch_1", "test_branch_2"}
-	suite.validation = NewBranchFieldsValidation(suite.repo, suite.branchNames[0], suite.branchNames[1])
+	suite.validation = NewBranchFieldsValidation(suite.mockRepo, suite.branchNames[0], suite.branchNames[1])
 }
 
 func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenAllFieldsAreValid_ShouldReturnNil() {
@@ -41,13 +37,14 @@ func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenRepoIs
 	err := suite.validation.ValidateBranchFields()
 
 	suite.NotNil(err)
-	suite.Equal("repo is nil", err.Error())
+	suite.Equal(NilRepoError, err)
 }
 
 func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenBranchNameIsEmpty_ShouldReturnError() {
-	suite.validation = NewBranchFieldsValidation(suite.repo, "", "")
+	suite.validation = NewBranchFieldsValidation(suite.mockRepo, "")
+
 	err := suite.validation.ValidateBranchFields()
 
 	suite.NotNil(err)
-	suite.Equal("branch name is empty", err.Error())
+	suite.Equal(EmptyBranchNameError, err)
 }
diff --git a/git/branch/errors.go b/git/branch/errors.go
new file mode 100644
index 0000000..fbdc83b
--- /dev/null
+++ b/git/branch/errors.go
@@ -0,0 +1,16 @@
+package branch
+
+type Error struct {
+	error
+	ErrorCode   string
+	ErrorString string
+}
+
+var (
+	NilRepoError         = Error{ErrorCode: "REPO_NIL_ERROR", ErrorString: "Repo is nil"}
+	EmptyBranchNameError = Error{ErrorCode: "BRANCH_EMPTY_ERROR", ErrorString: "Branch name(s) is empty"}
+)
+
+func (e Error) Error() string {
+	return e.ErrorString
+}

From 0608f9c6c97f386d1fa3948f3b8a61ae1cdb5621 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 24 Aug 2021 20:29:51 +0530
Subject: [PATCH 100/148] update branch validation to get branch names as
 params

---
 git/branch/branch_validation.go      | 18 ++++++++++--------
 git/branch/branch_validation_test.go | 20 ++++++++++++++------
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/git/branch/branch_validation.go b/git/branch/branch_validation.go
index e0d78e8..c3ae663 100644
--- a/git/branch/branch_validation.go
+++ b/git/branch/branch_validation.go
@@ -5,20 +5,23 @@ import (
 )
 
 type Validation interface {
-	ValidateBranchFields() error
+	ValidateBranchFields(branchNames ...string) error
 }
 
 type validateBranch struct {
-	repo       middleware.Repository
-	branchName []string
+	repo middleware.Repository
 }
 
-func (v validateBranch) ValidateBranchFields() error {
+func (v validateBranch) ValidateBranchFields(branchNames ...string) error {
 	if v.repo == nil {
 		return NilRepoError
 	}
 
-	for _, branchName := range v.branchName {
+	if len(branchNames) == 0 {
+		return EmptyBranchNameError
+	}
+
+	for _, branchName := range branchNames {
 		if branchName == "" {
 			return EmptyBranchNameError
 		}
@@ -27,9 +30,8 @@ func (v validateBranch) ValidateBranchFields() error {
 	return nil
 }
 
-func NewBranchFieldsValidation(repo middleware.Repository, branchName ...string) Validation {
+func NewBranchFieldsValidation(repo middleware.Repository) Validation {
 	return validateBranch{
-		repo:       repo,
-		branchName: branchName,
+		repo: repo,
 	}
 }
diff --git a/git/branch/branch_validation_test.go b/git/branch/branch_validation_test.go
index 1bbb6e9..7917904 100644
--- a/git/branch/branch_validation_test.go
+++ b/git/branch/branch_validation_test.go
@@ -22,29 +22,37 @@ func TestBranchFieldValidationTestSuite(t *testing.T) {
 func (suite *BranchFieldValidationTestSuite) SetupTest() {
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.branchNames = []string{"test_branch_1", "test_branch_2"}
-	suite.validation = NewBranchFieldsValidation(suite.mockRepo, suite.branchNames[0], suite.branchNames[1])
+	suite.validation = NewBranchFieldsValidation(suite.mockRepo)
 }
 
 func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenAllFieldsAreValid_ShouldReturnNil() {
-	err := suite.validation.ValidateBranchFields()
+	err := suite.validation.ValidateBranchFields("test_branch_1", "test_branch_2")
 
 	suite.Nil(err)
 }
 
 func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenRepoIsNil_ShouldReturnError() {
-	suite.validation = NewBranchFieldsValidation(nil, "test_branch")
-	err := suite.validation.ValidateBranchFields()
+	suite.validation = NewBranchFieldsValidation(nil)
+	err := suite.validation.ValidateBranchFields("test_branch_1", "test_branch_2")
 
 	suite.NotNil(err)
 	suite.Equal(NilRepoError, err)
 }
 
 func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenBranchNameIsEmpty_ShouldReturnError() {
-	suite.validation = NewBranchFieldsValidation(suite.mockRepo, "")
+	suite.validation = NewBranchFieldsValidation(suite.mockRepo)
 
 	err := suite.validation.ValidateBranchFields()
 
 	suite.NotNil(err)
 	suite.Equal(EmptyBranchNameError, err)
 }
+
+func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenOneOfBranchNamesIsEmpty_ShouldReturnError() {
+	suite.validation = NewBranchFieldsValidation(suite.mockRepo)
+
+	err := suite.validation.ValidateBranchFields("test_branch_1", "", "test_branch_3")
+
+	suite.NotNil(err)
+	suite.Equal(EmptyBranchNameError, err)
+}

From f797877ab09684a8f958562cf84ab9b667c5190d Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 24 Aug 2021 21:09:27 +0530
Subject: [PATCH 101/148] update create branch api with new middleware
 functions and revised UT suite

---
 git/branch/git_branch_add.go      | 41 +++++++-------
 git/branch/git_branch_add_test.go | 89 +++++++++++++++++++++++--------
 git/middleware/repository.go      |  5 ++
 mocks/mock_repository.go          | 15 ++++++
 4 files changed, 107 insertions(+), 43 deletions(-)

diff --git a/git/branch/git_branch_add.go b/git/branch/git_branch_add.go
index 7e8c6bd..cf8086c 100644
--- a/git/branch/git_branch_add.go
+++ b/git/branch/git_branch_add.go
@@ -3,6 +3,7 @@ package branch
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 )
 
@@ -11,56 +12,53 @@ type Add interface {
 }
 
 type addBranch struct {
-	repo         *git2go.Repository
-	branchName   string
-	remoteSwitch bool
-	targetCommit *git2go.Commit
+	repo             middleware.Repository
+	branchName       string
+	remoteSwitch     bool
+	targetCommit     *git2go.Commit
+	branchValidation Validation
 }
 
 func (a addBranch) AddBranch() error {
-	targetCommit := a.targetCommit
-	repo := a.repo
-	branchName := a.branchName
-
 	err := a.validateAddBranchFields()
 	if err != nil {
 		logger.Log(err.Error(), global.StatusError)
 		return err
 	}
 
-	head, headErr := repo.Head()
+	head, headErr := a.repo.Head()
 	if headErr != nil {
 		logger.Log(fmt.Sprintf("Unable to fetch HEAD -> %s", headErr.Error()), global.StatusError)
 		return headErr
 	}
 
-	targetCommit, validationErr := a.validateTargetCommit(targetCommit, repo, head)
+	targetCommit, validationErr := a.validateTargetCommit(a.targetCommit, a.repo, head)
 	if validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return validationErr
 	}
 
-	logger.Log(fmt.Sprintf("Adding new branch -> %s", branchName), global.StatusInfo)
+	logger.Log(fmt.Sprintf("Adding new branch -> %s", a.branchName), global.StatusInfo)
 
-	_, branchErr := repo.CreateBranch(branchName, targetCommit, false)
+	_, branchErr := a.repo.CreateBranch(a.branchName, targetCommit, false)
 	if branchErr != nil {
-		logger.Log(fmt.Sprintf("Failed to add branch - %s - %s", branchName, branchErr.Error()), global.StatusError)
+		logger.Log(fmt.Sprintf("Failed to add branch - %s - %s", a.branchName, branchErr.Error()), global.StatusError)
 		return branchErr
 	}
 
-	logger.Log(fmt.Sprintf("Added new branch - %s to the repo", branchName), global.StatusInfo)
+	logger.Log(fmt.Sprintf("Added new branch - %s to the repo", a.branchName), global.StatusInfo)
 	return nil
 }
 
 func (a addBranch) validateAddBranchFields() error {
-	err := NewBranchFieldsValidation(a.repo, a.branchName).ValidateBranchFields()
+	err := a.branchValidation.ValidateBranchFields(a.branchName)
 	if err != nil {
 		return err
 	}
 	return nil
 }
 
-func (a addBranch) validateTargetCommit(targetCommit *git2go.Commit, repo *git2go.Repository, head *git2go.Reference) (*git2go.Commit, error) {
+func (a addBranch) validateTargetCommit(targetCommit *git2go.Commit, repo middleware.Repository, head middleware.Reference) (*git2go.Commit, error) {
 	if targetCommit != nil {
 		return targetCommit, nil
 	}
@@ -73,11 +71,12 @@ func (a addBranch) validateTargetCommit(targetCommit *git2go.Commit, repo *git2g
 	return headCommit, nil
 }
 
-func NewAddBranch(repo *git2go.Repository, branchName string, remoteSwitch bool, targetCommit *git2go.Commit) Add {
+func NewAddBranch(repo middleware.Repository, branchName string, remoteSwitch bool, targetCommit *git2go.Commit, branchValidation Validation) Add {
 	return addBranch{
-		repo:         repo,
-		branchName:   branchName,
-		remoteSwitch: remoteSwitch,
-		targetCommit: targetCommit,
+		repo:             repo,
+		branchName:       branchName,
+		remoteSwitch:     remoteSwitch,
+		targetCommit:     targetCommit,
+		branchValidation: branchValidation,
 	}
 }
diff --git a/git/branch/git_branch_add_test.go b/git/branch/git_branch_add_test.go
index 5381d19..c312490 100644
--- a/git/branch/git_branch_add_test.go
+++ b/git/branch/git_branch_add_test.go
@@ -1,78 +1,123 @@
 package branch
 
 import (
+	"errors"
 	"fmt"
+	"github.com/golang/mock/gomock"
+	"github.com/google/uuid"
 	git2go "github.com/libgit2/git2go/v31"
+	branchMocks "github.com/neel1996/gitconvex/git/branch/mocks"
+	commitMocks "github.com/neel1996/gitconvex/git/commit/mocks"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
-	"path/filepath"
 	"testing"
 )
 
 type BranchAddTestSuite struct {
 	suite.Suite
-	repo       *git2go.Repository
-	noHeadRepo *git2go.Repository
-	branchName string
-	branchAdd  Add
+	repo                 middleware.Repository
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockReference        *mocks.MockReference
+	mockBranchValidation *branchMocks.MockValidation
+	mockCommit           *commitMocks.MockCommit
+	branchName           string
+	branchValidation     Validation
+	branchAdd            Add
 }
 
 func TestBranchAddTestSuite(t *testing.T) {
 	suite.Run(t, new(BranchAddTestSuite))
 }
 
+func (suite *BranchAddTestSuite) SetupSuite() {
+	suite.branchName = uuid.New().String()
+}
+
 func (suite *BranchAddTestSuite) SetupTest() {
 	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	if err != nil {
 		fmt.Println(err)
 	}
-	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
-	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
 
-	suite.repo = r
-	suite.noHeadRepo = noHeadRepo
-	suite.branchName = "test_1"
-	suite.branchAdd = NewAddBranch(suite.repo, suite.branchName, false, nil)
+	suite.repo = middleware.NewRepository(r)
+	suite.branchValidation = NewBranchFieldsValidation(suite.repo)
+
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockReference = mocks.NewMockReference(suite.mockController)
+	suite.mockCommit = commitMocks.NewMockCommit(suite.mockController)
+	suite.mockBranchValidation = branchMocks.NewMockValidation(suite.mockController)
+
+	suite.branchAdd = NewAddBranch(
+		suite.mockRepo,
+		suite.branchName,
+		false,
+		nil,
+		suite.mockBranchValidation,
+	)
 }
 
 func (suite *BranchAddTestSuite) TearDownSuite() {
 	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	_ = NewDeleteBranch(r, suite.branchName).DeleteBranch()
+	suite.mockController.Finish()
 }
 
 func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchAdditionSucceeds_ShouldReturnNil() {
+	suite.branchAdd = NewAddBranch(suite.repo, suite.branchName, false, nil, suite.branchValidation)
+
 	branchAddError := suite.branchAdd.AddBranch()
 
 	suite.Nil(branchAddError)
 }
 
-func (suite *BranchAddTestSuite) TestAddBranch_WhenRepoIsNil_ShouldReturnError() {
-	suite.branchAdd = NewAddBranch(nil, "", false, nil)
+func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchValidationFails_ShouldReturnError() {
+	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.branchName).Return(EmptyBranchNameError)
+
 	branchAddError := suite.branchAdd.AddBranch()
 
 	suite.NotNil(branchAddError)
 }
 
-func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchNameIsEmpty_ShouldReturnError() {
-	suite.branchAdd = NewAddBranch(suite.repo, "", false, nil)
+func (suite *BranchAddTestSuite) TestAddBranch_WhenHeadIsNil_ShouldReturnError() {
+	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.branchName).Return(nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("HEAD_ERROR"))
+
 	branchAddError := suite.branchAdd.AddBranch()
 
 	suite.NotNil(branchAddError)
 }
 
-func (suite *BranchAddTestSuite) TestAddBranch_WhenHeadIsNil_ShouldReturnError() {
-	suite.branchAdd = NewAddBranch(suite.noHeadRepo, suite.branchName, false, nil)
+func (suite *BranchAddTestSuite) TestAddBranch_WhenHeadCommitLookupFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("0608f9c6c97f386d1fa3948f3b8a61ae1cdb5621")
+
+	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.branchName).Return(nil)
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().Target().Return(oid)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, errors.New("LOOKUP_ERROR"))
+
 	branchAddError := suite.branchAdd.AddBranch()
 
 	suite.NotNil(branchAddError)
 }
 
-func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchAdditionFails_ShouldReturnError() {
-	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	suite.branchAdd = NewAddBranch(r, "master", false, nil)
+func (suite *BranchAddTestSuite) TestAddBranch_WhenCreateBranchFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("0608f9c6c97f386d1fa3948f3b8a61ae1cdb5621")
+	commit := &git2go.Commit{}
+
+	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.branchName).Return(nil)
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().Target().Return(oid)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(commit, nil)
+	suite.mockRepo.EXPECT().CreateBranch(
+		suite.branchName,
+		commit,
+		false,
+	).Return(nil, errors.New("BRANCH_CREATE_ERROR"))
 
-	//Adding duplicate branches
-	_ = suite.branchAdd.AddBranch()
 	branchAddError := suite.branchAdd.AddBranch()
 
 	suite.NotNil(branchAddError)
diff --git a/git/middleware/repository.go b/git/middleware/repository.go
index 85b6403..0973b95 100644
--- a/git/middleware/repository.go
+++ b/git/middleware/repository.go
@@ -12,6 +12,7 @@ type Repository interface {
 	Index() (Index, error)
 	CreateCommit(s string, signature *git.Signature, signature2 *git.Signature, message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error)
 	DiffTreeToTree(tree *git.Tree, tree2 *git.Tree, options *git.DiffOptions) (*git.Diff, error)
+	CreateBranch(string, *git.Commit, bool) (*git.Branch, error)
 }
 
 type repository struct {
@@ -27,6 +28,10 @@ func (r repository) CreateCommit(s string, signature *git.Signature, signature2
 	return r.repo.CreateCommit(s, signature, signature2, message, tree, parents...)
 }
 
+func (r repository) CreateBranch(branchName string, commit *git.Commit, force bool) (*git.Branch, error) {
+	return r.repo.CreateBranch(branchName, commit, force)
+}
+
 func (r repository) Head() (Reference, error) {
 	head, err := r.repo.Head()
 	if err != nil {
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
index 390fd65..d985707 100644
--- a/mocks/mock_repository.go
+++ b/mocks/mock_repository.go
@@ -35,6 +35,21 @@ func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
 	return m.recorder
 }
 
+// CreateBranch mocks base method.
+func (m *MockRepository) CreateBranch(arg0 string, arg1 *git.Commit, arg2 bool) (*git.Branch, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateBranch", arg0, arg1, arg2)
+	ret0, _ := ret[0].(*git.Branch)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateBranch indicates an expected call of CreateBranch.
+func (mr *MockRepositoryMockRecorder) CreateBranch(arg0, arg1, arg2 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBranch", reflect.TypeOf((*MockRepository)(nil).CreateBranch), arg0, arg1, arg2)
+}
+
 // CreateCommit mocks base method.
 func (m *MockRepository) CreateCommit(s string, signature, signature2 *git.Signature, message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error) {
 	m.ctrl.T.Helper()

From b3b9ec56e537c640a80e8a660c23ad832dfc104b Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 25 Aug 2021 23:50:18 +0530
Subject: [PATCH 102/148] add branch lookup function to repo middleware

---
 git/middleware/repository.go | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/git/middleware/repository.go b/git/middleware/repository.go
index 0973b95..0971794 100644
--- a/git/middleware/repository.go
+++ b/git/middleware/repository.go
@@ -13,6 +13,7 @@ type Repository interface {
 	CreateCommit(s string, signature *git.Signature, signature2 *git.Signature, message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error)
 	DiffTreeToTree(tree *git.Tree, tree2 *git.Tree, options *git.DiffOptions) (*git.Diff, error)
 	CreateBranch(string, *git.Commit, bool) (*git.Branch, error)
+	LookupBranch(name string, remote git.BranchType) (*git.Branch, error)
 }
 
 type repository struct {
@@ -52,6 +53,10 @@ func (r repository) LookupCommit(oid *git.Oid) (*git.Commit, error) {
 	return r.repo.LookupCommit(oid)
 }
 
+func (r repository) LookupBranch(branchName string, branchType git.BranchType) (*git.Branch, error) {
+	return r.repo.LookupBranch(branchName, branchType)
+}
+
 func (r repository) Walk() (RevWalk, error) {
 	walk, err := r.repo.Walk()
 

From 595a474b60205966749761db83bdd05d6a901ac6 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 25 Aug 2021 23:54:06 +0530
Subject: [PATCH 103/148] add branch checkout specific functions to repo
 middleware and update its mock

---
 git/middleware/repository.go | 18 +++++++++++----
 mocks/mock_repository.go     | 43 ++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+), 4 deletions(-)

diff --git a/git/middleware/repository.go b/git/middleware/repository.go
index 0971794..a263189 100644
--- a/git/middleware/repository.go
+++ b/git/middleware/repository.go
@@ -14,12 +14,22 @@ type Repository interface {
 	DiffTreeToTree(tree *git.Tree, tree2 *git.Tree, options *git.DiffOptions) (*git.Diff, error)
 	CreateBranch(string, *git.Commit, bool) (*git.Branch, error)
 	LookupBranch(name string, remote git.BranchType) (*git.Branch, error)
+	CheckoutTree(tree *git.Tree, c *git.CheckoutOptions) error
+	SetHead(name string) error
 }
 
 type repository struct {
 	repo *git.Repository
 }
 
+func (r repository) SetHead(name string) error {
+	return r.repo.SetHead(name)
+}
+
+func (r repository) CheckoutTree(tree *git.Tree, c *git.CheckoutOptions) error {
+	return r.repo.CheckoutTree(tree, c)
+}
+
 func (r repository) Remotes() Remotes {
 	return NewRemotes(r.repo.Remotes)
 }
@@ -57,6 +67,10 @@ func (r repository) LookupBranch(branchName string, branchType git.BranchType) (
 	return r.repo.LookupBranch(branchName, branchType)
 }
 
+func (r repository) LookupTree(id *git.Oid) (*git.Tree, error) {
+	return r.repo.LookupTree(id)
+}
+
 func (r repository) Walk() (RevWalk, error) {
 	walk, err := r.repo.Walk()
 
@@ -67,10 +81,6 @@ func (r repository) DefaultSignature() (*git.Signature, error) {
 	return r.repo.DefaultSignature()
 }
 
-func (r repository) LookupTree(id *git.Oid) (*git.Tree, error) {
-	return r.repo.LookupTree(id)
-}
-
 func (r repository) DiffTreeToTree(tree *git.Tree, tree2 *git.Tree, options *git.DiffOptions) (*git.Diff, error) {
 	return r.repo.DiffTreeToTree(tree, tree2, options)
 }
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
index d985707..5d12ec6 100644
--- a/mocks/mock_repository.go
+++ b/mocks/mock_repository.go
@@ -35,6 +35,20 @@ func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
 	return m.recorder
 }
 
+// CheckoutTree mocks base method.
+func (m *MockRepository) CheckoutTree(tree *git.Tree, c *git.CheckoutOptions) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CheckoutTree", tree, c)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// CheckoutTree indicates an expected call of CheckoutTree.
+func (mr *MockRepositoryMockRecorder) CheckoutTree(tree, c interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckoutTree", reflect.TypeOf((*MockRepository)(nil).CheckoutTree), tree, c)
+}
+
 // CreateBranch mocks base method.
 func (m *MockRepository) CreateBranch(arg0 string, arg1 *git.Commit, arg2 bool) (*git.Branch, error) {
 	m.ctrl.T.Helper()
@@ -130,6 +144,21 @@ func (mr *MockRepositoryMockRecorder) Index() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Index", reflect.TypeOf((*MockRepository)(nil).Index))
 }
 
+// LookupBranch mocks base method.
+func (m *MockRepository) LookupBranch(name string, remote git.BranchType) (*git.Branch, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "LookupBranch", name, remote)
+	ret0, _ := ret[0].(*git.Branch)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// LookupBranch indicates an expected call of LookupBranch.
+func (mr *MockRepositoryMockRecorder) LookupBranch(name, remote interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupBranch", reflect.TypeOf((*MockRepository)(nil).LookupBranch), name, remote)
+}
+
 // LookupCommit mocks base method.
 func (m *MockRepository) LookupCommit(oid *git.Oid) (*git.Commit, error) {
 	m.ctrl.T.Helper()
@@ -174,6 +203,20 @@ func (mr *MockRepositoryMockRecorder) Remotes() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Remotes", reflect.TypeOf((*MockRepository)(nil).Remotes))
 }
 
+// SetHead mocks base method.
+func (m *MockRepository) SetHead(name string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SetHead", name)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// SetHead indicates an expected call of SetHead.
+func (mr *MockRepositoryMockRecorder) SetHead(name interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHead", reflect.TypeOf((*MockRepository)(nil).SetHead), name)
+}
+
 // Walk mocks base method.
 func (m *MockRepository) Walk() (middleware.RevWalk, error) {
 	m.ctrl.T.Helper()

From c700ab2f776f4b03944d8f2d2361407a6b45b1d9 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 31 Aug 2021 22:19:53 +0530
Subject: [PATCH 104/148] add new factory for branch checkout api

---
 git/branch/checkout/checkout.go              | 17 +++++
 git/branch/checkout/checkout_factory.go      | 50 ++++++++++++++
 git/branch/checkout/checkout_factory_test.go | 71 ++++++++++++++++++++
 3 files changed, 138 insertions(+)
 create mode 100644 git/branch/checkout/checkout.go
 create mode 100644 git/branch/checkout/checkout_factory.go
 create mode 100644 git/branch/checkout/checkout_factory_test.go

diff --git a/git/branch/checkout/checkout.go b/git/branch/checkout/checkout.go
new file mode 100644
index 0000000..133ad83
--- /dev/null
+++ b/git/branch/checkout/checkout.go
@@ -0,0 +1,17 @@
+package checkout
+
+import "github.com/neel1996/gitconvex/global"
+
+var logger global.Logger
+
+type BranchDetails struct {
+	BranchName          string
+	ReferenceBranchName string
+	RemoteBranchName    string
+}
+
+type Checkout interface {
+	CheckoutBranch() error
+	GenerateBranchFields() BranchDetails
+	LogAndReturnError(err error) error
+}
diff --git a/git/branch/checkout/checkout_factory.go b/git/branch/checkout/checkout_factory.go
new file mode 100644
index 0000000..f2f60e7
--- /dev/null
+++ b/git/branch/checkout/checkout_factory.go
@@ -0,0 +1,50 @@
+package checkout
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"strings"
+)
+
+type Factory interface {
+	GetCheckoutAction() Checkout
+}
+
+type factory struct {
+	repo             middleware.Repository
+	branchName       string
+	branchValidation branch.Validation
+}
+
+func (f factory) GetCheckoutAction() Checkout {
+	logger.Log(fmt.Sprintf("Received branch %s", f.branchName), global.StatusInfo)
+	if validationErr := f.validateBranchFields(); validationErr != nil {
+		return nil
+	}
+
+	if strings.Contains(f.branchName, "remotes/") {
+		return NewCheckoutRemoteBranch(f.repo, f.branchName)
+	} else {
+		return NewCheckOutLocalBranch(f.repo, f.branchName)
+	}
+}
+
+func (f factory) validateBranchFields() error {
+	logger.Log("Validating branch fields before checkout", global.StatusInfo)
+
+	if err := f.branchValidation.ValidateBranchFields(f.branchName); err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return err
+	}
+	return nil
+}
+
+func NewCheckoutFactory(repo middleware.Repository, branchName string, branchValidation branch.Validation) Factory {
+	return factory{
+		repo:             repo,
+		branchName:       branchName,
+		branchValidation: branchValidation,
+	}
+}
diff --git a/git/branch/checkout/checkout_factory_test.go b/git/branch/checkout/checkout_factory_test.go
new file mode 100644
index 0000000..6f3d842
--- /dev/null
+++ b/git/branch/checkout/checkout_factory_test.go
@@ -0,0 +1,71 @@
+package checkout
+
+import (
+	"github.com/golang/mock/gomock"
+	"github.com/neel1996/gitconvex/git/branch"
+	branchMocks "github.com/neel1996/gitconvex/git/branch/mocks"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type CheckoutFactoryTestSuite struct {
+	suite.Suite
+	repo                 middleware.Repository
+	branchName           string
+	remoteBranchName     string
+	branchValidation     branch.Validation
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockBranchValidation *branchMocks.MockValidation
+	checkoutFactory      Factory
+}
+
+func TestCheckoutFactoryTestSuite(t *testing.T) {
+	suite.Run(t, new(CheckoutFactoryTestSuite))
+}
+
+func (suite *CheckoutFactoryTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockBranchValidation = branchMocks.NewMockValidation(suite.mockController)
+	suite.branchName = "test_branch"
+	suite.remoteBranchName = "remotes/origin/test_branch"
+}
+
+func (suite *CheckoutFactoryTestSuite) TearDownTest() {
+	suite.mockController.Finish()
+}
+
+func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsLocal_ShouldReturnLocalCheckoutAction() {
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.branchName, suite.mockBranchValidation)
+
+	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.branchName).Return(nil)
+
+	wantAction := NewCheckOutLocalBranch(suite.mockRepo, suite.branchName)
+	gotAction := suite.checkoutFactory.GetCheckoutAction()
+
+	suite.Equal(wantAction, gotAction)
+}
+
+func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsRemote_ShouldReturnRemoteCheckoutAction() {
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.remoteBranchName, suite.mockBranchValidation)
+
+	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.remoteBranchName).Return(nil)
+
+	wantAction := NewCheckoutRemoteBranch(suite.mockRepo, suite.remoteBranchName)
+	gotAction := suite.checkoutFactory.GetCheckoutAction()
+
+	suite.Equal(wantAction, gotAction)
+}
+
+func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchValidationFails_ShouldReturnNil() {
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, "", suite.mockBranchValidation)
+
+	suite.mockBranchValidation.EXPECT().ValidateBranchFields("").Return(branch.EmptyBranchNameError)
+
+	gotAction := suite.checkoutFactory.GetCheckoutAction()
+
+	suite.Nil(gotAction)
+}

From ed16103de9747df85042f5dba533b289b73f4cf7 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 31 Aug 2021 22:49:12 +0530
Subject: [PATCH 105/148] add new branch middleware and mocks

---
 generate_all_mocks.sh        |  1 +
 git/middleware/branch.go     | 21 ++++++++++++++++
 git/middleware/repository.go | 16 +++++++++++-
 mocks/mock_branch.go         | 49 ++++++++++++++++++++++++++++++++++++
 mocks/mock_repository.go     | 37 ++++++++++++++++++++++++---
 5 files changed, 119 insertions(+), 5 deletions(-)
 create mode 100644 git/middleware/branch.go
 create mode 100644 mocks/mock_branch.go

diff --git a/generate_all_mocks.sh b/generate_all_mocks.sh
index 9a8fc3a..a64cc87 100755
--- a/generate_all_mocks.sh
+++ b/generate_all_mocks.sh
@@ -5,6 +5,7 @@ mockgen -source=git/middleware/repository.go -destination=mocks/mock_repository.
 mockgen -source=git/middleware/walk.go -destination=mocks/mock_walk.go -package=mocks
 mockgen -source=git/middleware/reference.go -destination=mocks/mock_reference.go -package=mocks
 mockgen -source=git/middleware/index.go -destination=mocks/mock_index.go -package=mocks
+mockgen -source=git/middleware/branch.go -destination=mocks/mock_branch.go -package=mocks
 
 # Commit mocks
 mockgen -source=git/commit/git_list_all_commit_logs.go -destination=git/commit/mocks/mock_git_list_all_commit_logs.go -package=mocks
diff --git a/git/middleware/branch.go b/git/middleware/branch.go
new file mode 100644
index 0000000..b8f50ea
--- /dev/null
+++ b/git/middleware/branch.go
@@ -0,0 +1,21 @@
+package middleware
+
+import git2go "github.com/libgit2/git2go/v31"
+
+type Branch interface {
+	Target() *git2go.Oid
+}
+
+type branch struct {
+	branch *git2go.Branch
+}
+
+func (b branch) Target() *git2go.Oid {
+	return b.branch.Target()
+}
+
+func NewBranch(gitBranch *git2go.Branch) Branch {
+	return branch{
+		branch: gitBranch,
+	}
+}
diff --git a/git/middleware/repository.go b/git/middleware/repository.go
index a263189..9bb291e 100644
--- a/git/middleware/repository.go
+++ b/git/middleware/repository.go
@@ -13,9 +13,11 @@ type Repository interface {
 	CreateCommit(s string, signature *git.Signature, signature2 *git.Signature, message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error)
 	DiffTreeToTree(tree *git.Tree, tree2 *git.Tree, options *git.DiffOptions) (*git.Diff, error)
 	CreateBranch(string, *git.Commit, bool) (*git.Branch, error)
-	LookupBranch(name string, remote git.BranchType) (*git.Branch, error)
+	LookupBranch(branchName string, branchType git.BranchType) (*git.Branch, error)
+	LookupBranchV2(branchName string, branchType git.BranchType) (Branch, error)
 	CheckoutTree(tree *git.Tree, c *git.CheckoutOptions) error
 	SetHead(name string) error
+	GetGitRepository() *git.Repository
 }
 
 type repository struct {
@@ -67,6 +69,14 @@ func (r repository) LookupBranch(branchName string, branchType git.BranchType) (
 	return r.repo.LookupBranch(branchName, branchType)
 }
 
+func (r repository) LookupBranchV2(branchName string, branchType git.BranchType) (Branch, error) {
+	gitBranch, err := r.repo.LookupBranch(branchName, branchType)
+	if err != nil {
+		return nil, err
+	}
+	return NewBranch(gitBranch), nil
+}
+
 func (r repository) LookupTree(id *git.Oid) (*git.Tree, error) {
 	return r.repo.LookupTree(id)
 }
@@ -85,6 +95,10 @@ func (r repository) DiffTreeToTree(tree *git.Tree, tree2 *git.Tree, options *git
 	return r.repo.DiffTreeToTree(tree, tree2, options)
 }
 
+func (r repository) GetGitRepository() *git.Repository {
+	return r.repo
+}
+
 func NewRepository(repo *git.Repository) Repository {
 	return repository{repo: repo}
 }
diff --git a/mocks/mock_branch.go b/mocks/mock_branch.go
new file mode 100644
index 0000000..6038547
--- /dev/null
+++ b/mocks/mock_branch.go
@@ -0,0 +1,49 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/branch.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockBranch is a mock of Branch interface.
+type MockBranch struct {
+	ctrl     *gomock.Controller
+	recorder *MockBranchMockRecorder
+}
+
+// MockBranchMockRecorder is the mock recorder for MockBranch.
+type MockBranchMockRecorder struct {
+	mock *MockBranch
+}
+
+// NewMockBranch creates a new mock instance.
+func NewMockBranch(ctrl *gomock.Controller) *MockBranch {
+	mock := &MockBranch{ctrl: ctrl}
+	mock.recorder = &MockBranchMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockBranch) EXPECT() *MockBranchMockRecorder {
+	return m.recorder
+}
+
+// Target mocks base method.
+func (m *MockBranch) Target() *git.Oid {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Target")
+	ret0, _ := ret[0].(*git.Oid)
+	return ret0
+}
+
+// Target indicates an expected call of Target.
+func (mr *MockBranchMockRecorder) Target() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Target", reflect.TypeOf((*MockBranch)(nil).Target))
+}
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
index 5d12ec6..f001385 100644
--- a/mocks/mock_repository.go
+++ b/mocks/mock_repository.go
@@ -114,6 +114,20 @@ func (mr *MockRepositoryMockRecorder) DiffTreeToTree(tree, tree2, options interf
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DiffTreeToTree", reflect.TypeOf((*MockRepository)(nil).DiffTreeToTree), tree, tree2, options)
 }
 
+// GetGitRepository mocks base method.
+func (m *MockRepository) GetGitRepository() *git.Repository {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetGitRepository")
+	ret0, _ := ret[0].(*git.Repository)
+	return ret0
+}
+
+// GetGitRepository indicates an expected call of GetGitRepository.
+func (mr *MockRepositoryMockRecorder) GetGitRepository() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGitRepository", reflect.TypeOf((*MockRepository)(nil).GetGitRepository))
+}
+
 // Head mocks base method.
 func (m *MockRepository) Head() (middleware.Reference, error) {
 	m.ctrl.T.Helper()
@@ -145,18 +159,33 @@ func (mr *MockRepositoryMockRecorder) Index() *gomock.Call {
 }
 
 // LookupBranch mocks base method.
-func (m *MockRepository) LookupBranch(name string, remote git.BranchType) (*git.Branch, error) {
+func (m *MockRepository) LookupBranch(branchName string, branchType git.BranchType) (*git.Branch, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "LookupBranch", name, remote)
+	ret := m.ctrl.Call(m, "LookupBranch", branchName, branchType)
 	ret0, _ := ret[0].(*git.Branch)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
 // LookupBranch indicates an expected call of LookupBranch.
-func (mr *MockRepositoryMockRecorder) LookupBranch(name, remote interface{}) *gomock.Call {
+func (mr *MockRepositoryMockRecorder) LookupBranch(branchName, branchType interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupBranch", reflect.TypeOf((*MockRepository)(nil).LookupBranch), branchName, branchType)
+}
+
+// LookupBranchV2 mocks base method.
+func (m *MockRepository) LookupBranchV2(branchName string, branchType git.BranchType) (middleware.Branch, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "LookupBranchV2", branchName, branchType)
+	ret0, _ := ret[0].(middleware.Branch)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// LookupBranchV2 indicates an expected call of LookupBranchV2.
+func (mr *MockRepositoryMockRecorder) LookupBranchV2(branchName, branchType interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupBranch", reflect.TypeOf((*MockRepository)(nil).LookupBranch), name, remote)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupBranchV2", reflect.TypeOf((*MockRepository)(nil).LookupBranchV2), branchName, branchType)
 }
 
 // LookupCommit mocks base method.

From 3c7ae1b8197bad80d377998e8864ce5ca07d44da Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 31 Aug 2021 23:21:30 +0530
Subject: [PATCH 106/148] add new factory method for checking out local branch

---
 generate_all_mocks.sh                         |   1 +
 git/branch/checkout/checkout_local_branch.go  |  73 ++++++++++
 .../checkout/checkout_local_branch_test.go    | 128 ++++++++++++++++++
 git/branch/mocks/mock_branch_validation.go    |  52 +++++++
 git/middleware/repository.go                  |   9 ++
 mocks/mock_commit.go                          |  93 +++++++++++++
 mocks/mock_repository.go                      |  15 ++
 7 files changed, 371 insertions(+)
 create mode 100644 git/branch/checkout/checkout_local_branch.go
 create mode 100644 git/branch/checkout/checkout_local_branch_test.go
 create mode 100644 git/branch/mocks/mock_branch_validation.go
 create mode 100644 mocks/mock_commit.go

diff --git a/generate_all_mocks.sh b/generate_all_mocks.sh
index a64cc87..b819283 100755
--- a/generate_all_mocks.sh
+++ b/generate_all_mocks.sh
@@ -6,6 +6,7 @@ mockgen -source=git/middleware/walk.go -destination=mocks/mock_walk.go -package=
 mockgen -source=git/middleware/reference.go -destination=mocks/mock_reference.go -package=mocks
 mockgen -source=git/middleware/index.go -destination=mocks/mock_index.go -package=mocks
 mockgen -source=git/middleware/branch.go -destination=mocks/mock_branch.go -package=mocks
+mockgen -source=git/middleware/commit.go -destination=mocks/mock_commit.go -package=mocks
 
 # Commit mocks
 mockgen -source=git/commit/git_list_all_commit_logs.go -destination=git/commit/mocks/mock_git_list_all_commit_logs.go -package=mocks
diff --git a/git/branch/checkout/checkout_local_branch.go b/git/branch/checkout/checkout_local_branch.go
new file mode 100644
index 0000000..87db5a4
--- /dev/null
+++ b/git/branch/checkout/checkout_local_branch.go
@@ -0,0 +1,73 @@
+package checkout
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type checkOutLocalBranch struct {
+	repo       middleware.Repository
+	branchName string
+}
+
+func (c checkOutLocalBranch) CheckoutBranch() error {
+	repo := c.repo
+	branchName := c.branchName
+
+	logger.Log(fmt.Sprintf("Initiating local branch checkout for %s", branchName), global.StatusInfo)
+
+	branch, branchErr := repo.LookupBranchV2(branchName, git2go.BranchLocal)
+	if branchErr != nil {
+		return c.LogAndReturnError(branchErr)
+	}
+
+	commit, lookupCommitErr := repo.LookupCommitV2(branch.Target())
+	if lookupCommitErr != nil {
+		return c.LogAndReturnError(lookupCommitErr)
+	}
+
+	tree, treeErr := commit.Tree()
+	if treeErr != nil {
+		return c.LogAndReturnError(treeErr)
+	}
+
+	checkoutErr := repo.CheckoutTree(tree, &git2go.CheckoutOptions{
+		Strategy:       git2go.CheckoutSafe,
+		DisableFilters: false,
+	})
+
+	if checkoutErr != nil {
+		return c.LogAndReturnError(checkoutErr)
+	}
+
+	err := repo.SetHead(c.GenerateBranchFields().ReferenceBranchName)
+	if err != nil {
+		return c.LogAndReturnError(err)
+	}
+
+	logger.Log(fmt.Sprintf("Local branch %v has been checked out", c.branchName), global.StatusInfo)
+	return nil
+}
+
+func (c checkOutLocalBranch) GenerateBranchFields() BranchDetails {
+	referenceBranchName := "refs/heads/" + c.branchName
+
+	return BranchDetails{
+		BranchName:          c.branchName,
+		ReferenceBranchName: referenceBranchName,
+	}
+}
+
+func (c checkOutLocalBranch) LogAndReturnError(err error) error {
+	logger.Log(err.Error(), global.StatusError)
+	return err
+}
+
+func NewCheckOutLocalBranch(repo middleware.Repository, branchName string) Checkout {
+	return checkOutLocalBranch{
+		repo:       repo,
+		branchName: branchName,
+	}
+}
diff --git a/git/branch/checkout/checkout_local_branch_test.go b/git/branch/checkout/checkout_local_branch_test.go
new file mode 100644
index 0000000..edb4ed9
--- /dev/null
+++ b/git/branch/checkout/checkout_local_branch_test.go
@@ -0,0 +1,128 @@
+package checkout
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type CheckOutLocalBranchTestSuite struct {
+	suite.Suite
+	repo                middleware.Repository
+	mockController      *gomock.Controller
+	mockRepo            *mocks.MockRepository
+	mockBranch          *mocks.MockBranch
+	mockCommit          *mocks.MockCommit
+	branchName          string
+	checkOutLocalBranch Checkout
+}
+
+func TestCheckOutLocalBranchTestSuite(t *testing.T) {
+	suite.Run(t, new(CheckOutLocalBranchTestSuite))
+}
+
+func (suite *CheckOutLocalBranchTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.branchName = "test_checkout"
+
+	_ = branch.NewAddBranch(
+		suite.repo,
+		suite.branchName,
+		false,
+		nil,
+		branch.NewBranchFieldsValidation(suite.repo),
+	).AddBranch()
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TearDownSuite() {
+	branch.NewDeleteBranch(suite.repo.GetGitRepository(), suite.branchName)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockBranch = mocks.NewMockBranch(suite.mockController)
+	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
+
+	suite.checkOutLocalBranch = NewCheckOutLocalBranch(suite.mockRepo, suite.branchName)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TearDownTest() {
+	suite.mockController.Finish()
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenBranchIsValid_ShouldCheckoutLocalBranch() {
+	suite.checkOutLocalBranch = NewCheckOutLocalBranch(suite.repo, suite.branchName)
+
+	err := suite.checkOutLocalBranch.CheckoutBranch()
+
+	suite.Nil(err)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenBranchLookupFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	err := suite.checkOutLocalBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenCommitLookupFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	err := suite.checkOutLocalBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenFetchCommitTreeFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(nil, errors.New("TREE_ERROR"))
+
+	err := suite.checkOutLocalBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenCheckoutTreeFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(errors.New("TREE_CHECKOUT_ERROR"))
+
+	err := suite.checkOutLocalBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenSetHeadFails_ShouldReturnError() {
+	referenceName := "refs/heads/" + suite.branchName
+
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
+	suite.mockRepo.EXPECT().SetHead(referenceName).Return(errors.New("SET_HEAD_ERROR"))
+
+	err := suite.checkOutLocalBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
diff --git a/git/branch/mocks/mock_branch_validation.go b/git/branch/mocks/mock_branch_validation.go
new file mode 100644
index 0000000..ad3c118
--- /dev/null
+++ b/git/branch/mocks/mock_branch_validation.go
@@ -0,0 +1,52 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/branch/branch_validation.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockValidation is a mock of Validation interface.
+type MockValidation struct {
+	ctrl     *gomock.Controller
+	recorder *MockValidationMockRecorder
+}
+
+// MockValidationMockRecorder is the mock recorder for MockValidation.
+type MockValidationMockRecorder struct {
+	mock *MockValidation
+}
+
+// NewMockValidation creates a new mock instance.
+func NewMockValidation(ctrl *gomock.Controller) *MockValidation {
+	mock := &MockValidation{ctrl: ctrl}
+	mock.recorder = &MockValidationMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockValidation) EXPECT() *MockValidationMockRecorder {
+	return m.recorder
+}
+
+// ValidateBranchFields mocks base method.
+func (m *MockValidation) ValidateBranchFields(branchNames ...string) error {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{}
+	for _, a := range branchNames {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ValidateBranchFields", varargs...)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// ValidateBranchFields indicates an expected call of ValidateBranchFields.
+func (mr *MockValidationMockRecorder) ValidateBranchFields(branchNames ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateBranchFields", reflect.TypeOf((*MockValidation)(nil).ValidateBranchFields), branchNames...)
+}
diff --git a/git/middleware/repository.go b/git/middleware/repository.go
index 9bb291e..bb6ca0b 100644
--- a/git/middleware/repository.go
+++ b/git/middleware/repository.go
@@ -7,6 +7,7 @@ type Repository interface {
 	Walk() (RevWalk, error)
 	Head() (Reference, error)
 	LookupCommit(oid *git.Oid) (*git.Commit, error)
+	LookupCommitV2(oid *git.Oid) (Commit, error)
 	DefaultSignature() (*git.Signature, error)
 	LookupTree(id *git.Oid) (*git.Tree, error)
 	Index() (Index, error)
@@ -65,6 +66,14 @@ func (r repository) LookupCommit(oid *git.Oid) (*git.Commit, error) {
 	return r.repo.LookupCommit(oid)
 }
 
+func (r repository) LookupCommitV2(oid *git.Oid) (Commit, error) {
+	gitCommit, err := r.repo.LookupCommit(oid)
+	if err != nil {
+		return nil, err
+	}
+	return NewCommit(gitCommit), nil
+}
+
 func (r repository) LookupBranch(branchName string, branchType git.BranchType) (*git.Branch, error) {
 	return r.repo.LookupBranch(branchName, branchType)
 }
diff --git a/mocks/mock_commit.go b/mocks/mock_commit.go
new file mode 100644
index 0000000..e6b0f84
--- /dev/null
+++ b/mocks/mock_commit.go
@@ -0,0 +1,93 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/commit.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+	middleware "github.com/neel1996/gitconvex/git/middleware"
+)
+
+// MockCommit is a mock of Commit interface.
+type MockCommit struct {
+	ctrl     *gomock.Controller
+	recorder *MockCommitMockRecorder
+}
+
+// MockCommitMockRecorder is the mock recorder for MockCommit.
+type MockCommitMockRecorder struct {
+	mock *MockCommit
+}
+
+// NewMockCommit creates a new mock instance.
+func NewMockCommit(ctrl *gomock.Controller) *MockCommit {
+	mock := &MockCommit{ctrl: ctrl}
+	mock.recorder = &MockCommitMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockCommit) EXPECT() *MockCommitMockRecorder {
+	return m.recorder
+}
+
+// Id mocks base method.
+func (m *MockCommit) Id() *git.Oid {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Id")
+	ret0, _ := ret[0].(*git.Oid)
+	return ret0
+}
+
+// Id indicates an expected call of Id.
+func (mr *MockCommitMockRecorder) Id() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockCommit)(nil).Id))
+}
+
+// Parent mocks base method.
+func (m *MockCommit) Parent(arg0 uint) middleware.Commit {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Parent", arg0)
+	ret0, _ := ret[0].(middleware.Commit)
+	return ret0
+}
+
+// Parent indicates an expected call of Parent.
+func (mr *MockCommitMockRecorder) Parent(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Parent", reflect.TypeOf((*MockCommit)(nil).Parent), arg0)
+}
+
+// ParentCount mocks base method.
+func (m *MockCommit) ParentCount() uint {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ParentCount")
+	ret0, _ := ret[0].(uint)
+	return ret0
+}
+
+// ParentCount indicates an expected call of ParentCount.
+func (mr *MockCommitMockRecorder) ParentCount() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParentCount", reflect.TypeOf((*MockCommit)(nil).ParentCount))
+}
+
+// Tree mocks base method.
+func (m *MockCommit) Tree() (*git.Tree, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Tree")
+	ret0, _ := ret[0].(*git.Tree)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Tree indicates an expected call of Tree.
+func (mr *MockCommitMockRecorder) Tree() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Tree", reflect.TypeOf((*MockCommit)(nil).Tree))
+}
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
index f001385..7446e2c 100644
--- a/mocks/mock_repository.go
+++ b/mocks/mock_repository.go
@@ -203,6 +203,21 @@ func (mr *MockRepositoryMockRecorder) LookupCommit(oid interface{}) *gomock.Call
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupCommit", reflect.TypeOf((*MockRepository)(nil).LookupCommit), oid)
 }
 
+// LookupCommitV2 mocks base method.
+func (m *MockRepository) LookupCommitV2(oid *git.Oid) (middleware.Commit, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "LookupCommitV2", oid)
+	ret0, _ := ret[0].(middleware.Commit)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// LookupCommitV2 indicates an expected call of LookupCommitV2.
+func (mr *MockRepositoryMockRecorder) LookupCommitV2(oid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupCommitV2", reflect.TypeOf((*MockRepository)(nil).LookupCommitV2), oid)
+}
+
 // LookupTree mocks base method.
 func (m *MockRepository) LookupTree(id *git.Oid) (*git.Tree, error) {
 	m.ctrl.T.Helper()

From 18b19884272abe1b720decdf6357f720130bb127 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 1 Sep 2021 23:39:14 +0530
Subject: [PATCH 107/148] add new pre-test script to delete the test repo
 before running tests

---
 Makefile                          | 2 ++
 build_scripts/remove_test_repo.sh | 4 ++++
 2 files changed, 6 insertions(+)
 create mode 100644 build_scripts/remove_test_repo.sh

diff --git a/Makefile b/Makefile
index 8b72576..8e8c807 100644
--- a/Makefile
+++ b/Makefile
@@ -37,6 +37,7 @@ test:
 	export GITCONVEX_DEFAULT_PATH="$(PWD)/gitconvex-test" && \
 	rm -rf $$GITCONVEX_TEST_REPO && \
  	go clean --cache && \
+ 	./build_scripts/remove_test_repo.sh && \
  	./build_scripts/clone_test_repo.sh && \
  	go test ./... -count=1 -cover -coverprofile=coverage.out && \
 	rm -rf $$GITCONVEX_TEST_REPO
@@ -46,6 +47,7 @@ test-pretty:
 	export GITCONVEX_DEFAULT_PATH="$(PWD)/gitconvex-test" && \
 	rm -rf $$GITCONVEX_TEST_REPO && \
  	go clean --cache && \
+ 	./build_scripts/remove_test_repo.sh && \
  	./build_scripts/clone_test_repo.sh && \
  	gotestsum ./... -count=1 -cover -coverprofile=coverage.out && \
 	rm -rf $$GITCONVEX_TEST_REPO
diff --git a/build_scripts/remove_test_repo.sh b/build_scripts/remove_test_repo.sh
new file mode 100644
index 0000000..8189f89
--- /dev/null
+++ b/build_scripts/remove_test_repo.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+echo "Removing test repo $GITCONVEX_TEST_REPO"
+rm -rf $GITCONVEX_TEST_REPO
\ No newline at end of file

From 55064a89c66aa5a42efef15183b452085702aa0a Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 2 Sep 2021 23:50:27 +0530
Subject: [PATCH 108/148] add factory method for remote branch checkout

---
 generate_all_mocks.sh                         |   6 +-
 git/branch/checkout/checkout_factory.go       |   4 +-
 git/branch/checkout/checkout_factory_test.go  |   5 +-
 git/branch/checkout/checkout_remote_branch.go | 108 +++++++++++
 .../checkout/checkout_remote_branch_test.go   | 183 ++++++++++++++++++
 git/branch/git_branch_add.go                  |  19 ++
 git/branch/mocks/git_branch_add.go            |  63 ++++++
 git/commit/mocks/mock_commit.go               |  93 ---------
 git/middleware/commit.go                      |   5 +
 mocks/mock_commit.go                          |  14 ++
 10 files changed, 402 insertions(+), 98 deletions(-)
 create mode 100644 git/branch/checkout/checkout_remote_branch.go
 create mode 100644 git/branch/checkout/checkout_remote_branch_test.go
 create mode 100644 git/branch/mocks/git_branch_add.go
 delete mode 100644 git/commit/mocks/mock_commit.go

diff --git a/generate_all_mocks.sh b/generate_all_mocks.sh
index b819283..4894f0b 100755
--- a/generate_all_mocks.sh
+++ b/generate_all_mocks.sh
@@ -10,10 +10,12 @@ mockgen -source=git/middleware/commit.go -destination=mocks/mock_commit.go -pack
 
 # Commit mocks
 mockgen -source=git/commit/git_list_all_commit_logs.go -destination=git/commit/mocks/mock_git_list_all_commit_logs.go -package=mocks
-mockgen -source=git/middleware/commit.go -destination=git/commit/mocks/mock_commit.go -package=mocks
 mockgen -source=git/commit/git_commit_file_history.go -destination=git/commit/mocks/mock_git_commit_file_history.go -package=mocks
 
 # Remote mocks
 mockgen -source=git/remote/remote_validation.go -destination=git/remote/mocks/mock_remote_validation.go -package=mocks
 mockgen -source=git/remote/git_remote_list.go -destination=git/remote/mocks/mock_git_remote_list.go -package=mocks
-mockgen -source=git/middleware/remotes.go -destination=git/remote/mocks/mock_remotes.go -package=mocks
\ No newline at end of file
+mockgen -source=git/middleware/remotes.go -destination=git/remote/mocks/mock_remotes.go -package=mocks
+
+# Branch mocks
+mockgen -source=git/branch/git_branch_add.go  -destination=git/branch/mocks/git_branch_add.go -package=mocks
\ No newline at end of file
diff --git a/git/branch/checkout/checkout_factory.go b/git/branch/checkout/checkout_factory.go
index f2f60e7..cecbb2c 100644
--- a/git/branch/checkout/checkout_factory.go
+++ b/git/branch/checkout/checkout_factory.go
@@ -25,7 +25,9 @@ func (f factory) GetCheckoutAction() Checkout {
 	}
 
 	if strings.Contains(f.branchName, "remotes/") {
-		return NewCheckoutRemoteBranch(f.repo, f.branchName)
+		addBranch := branch.NewAddBranchV2(f.repo, f.branchValidation)
+
+		return NewCheckoutRemoteBranch(f.repo, f.branchName, addBranch)
 	} else {
 		return NewCheckOutLocalBranch(f.repo, f.branchName)
 	}
diff --git a/git/branch/checkout/checkout_factory_test.go b/git/branch/checkout/checkout_factory_test.go
index 6f3d842..bd622df 100644
--- a/git/branch/checkout/checkout_factory_test.go
+++ b/git/branch/checkout/checkout_factory_test.go
@@ -15,7 +15,7 @@ type CheckoutFactoryTestSuite struct {
 	repo                 middleware.Repository
 	branchName           string
 	remoteBranchName     string
-	branchValidation     branch.Validation
+	addBranch            branch.Add
 	mockController       *gomock.Controller
 	mockRepo             *mocks.MockRepository
 	mockBranchValidation *branchMocks.MockValidation
@@ -32,6 +32,7 @@ func (suite *CheckoutFactoryTestSuite) SetupTest() {
 	suite.mockBranchValidation = branchMocks.NewMockValidation(suite.mockController)
 	suite.branchName = "test_branch"
 	suite.remoteBranchName = "remotes/origin/test_branch"
+	suite.addBranch = branch.NewAddBranchV2(suite.mockRepo, suite.mockBranchValidation)
 }
 
 func (suite *CheckoutFactoryTestSuite) TearDownTest() {
@@ -54,7 +55,7 @@ func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsRemote_
 
 	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.remoteBranchName).Return(nil)
 
-	wantAction := NewCheckoutRemoteBranch(suite.mockRepo, suite.remoteBranchName)
+	wantAction := NewCheckoutRemoteBranch(suite.mockRepo, suite.remoteBranchName, suite.addBranch)
 	gotAction := suite.checkoutFactory.GetCheckoutAction()
 
 	suite.Equal(wantAction, gotAction)
diff --git a/git/branch/checkout/checkout_remote_branch.go b/git/branch/checkout/checkout_remote_branch.go
new file mode 100644
index 0000000..c336acb
--- /dev/null
+++ b/git/branch/checkout/checkout_remote_branch.go
@@ -0,0 +1,108 @@
+package checkout
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"strings"
+)
+
+type checkOutRemoteBranch struct {
+	repo       middleware.Repository
+	branchName string
+	addBranch  branch.Add
+}
+
+func (c checkOutRemoteBranch) CheckoutBranch() error {
+	repo := c.repo
+	branchName := c.branchName
+
+	logger.Log(fmt.Sprintf("Initiating remote branch checkout for %s", branchName), global.StatusInfo)
+
+	branchFields := c.GenerateBranchFields()
+
+	logger.Log(fmt.Sprintf("Branch - %s is a remote branch. Trying with intermediate remote fetch!", branchName), global.StatusWarning)
+	remoteBranch, remoteBranchErr := repo.LookupBranchV2(branchFields.RemoteBranchName, git2go.BranchRemote)
+	if remoteBranchErr != nil {
+		return c.LogAndReturnError(remoteBranchErr)
+	}
+
+	remoteHead := remoteBranch.Target()
+	remoteCommit, remoteCommitErr := repo.LookupCommitV2(remoteHead)
+	if remoteCommitErr != nil {
+		return c.LogAndReturnError(remoteCommitErr)
+
+	}
+
+	remoteTree, remoteTreeErr := remoteCommit.Tree()
+	if remoteTreeErr != nil {
+		return c.LogAndReturnError(remoteTreeErr)
+	}
+
+	if checkoutErr := repo.CheckoutTree(remoteTree, &git2go.CheckoutOptions{Strategy: git2go.CheckoutSafe}); checkoutErr != nil {
+		return c.LogAndReturnError(checkoutErr)
+	}
+
+	_, localLookupErr := repo.LookupBranchV2(branchFields.BranchName, git2go.BranchLocal)
+	if localLookupErr != nil {
+		logger.Log(localLookupErr.Error(), global.StatusError)
+		gitCommit := remoteCommit.GetGitCommit()
+		return c.addAndCheckoutNewBranch(gitCommit, branchFields.ReferenceBranchName)
+	}
+
+	if err := repo.SetHead(branchFields.ReferenceBranchName); err != nil {
+		return c.LogAndReturnError(err)
+	}
+
+	logger.Log(fmt.Sprintf("Remote branch %v has been checked out", branchFields.RemoteBranchName), global.StatusInfo)
+
+	return nil
+}
+
+func (c checkOutRemoteBranch) addAndCheckoutNewBranch(remoteCommit *git2go.Commit, referenceBranchName string) error {
+	logger.Log("Adding local branch for remote reference", global.StatusInfo)
+
+	branchAddError := c.addBranch.AddBranchV2(c.branchName, false, remoteCommit)
+	if branchAddError != nil {
+		logger.Log("Error while adding branch "+branchAddError.Error(), global.StatusError)
+		return branchAddError
+	}
+
+	if err := c.repo.SetHead(referenceBranchName); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c checkOutRemoteBranch) GenerateBranchFields() BranchDetails {
+	referenceBranchName := "refs/heads/" + c.splitAndReturnBranchName("/", c.branchName)
+	remoteBranchName := c.splitAndReturnBranchName("remotes/", c.branchName)
+	branchName := c.splitAndReturnBranchName("/", c.branchName)
+
+	return BranchDetails{
+		BranchName:          branchName,
+		ReferenceBranchName: referenceBranchName,
+		RemoteBranchName:    remoteBranchName,
+	}
+}
+
+func (c checkOutRemoteBranch) LogAndReturnError(err error) error {
+	logger.Log(err.Error(), global.StatusError)
+	return err
+}
+
+func (c checkOutRemoteBranch) splitAndReturnBranchName(delimiter string, branchName string) string {
+	splitString := strings.Split(branchName, delimiter)
+	return splitString[len(splitString)-1]
+}
+
+func NewCheckoutRemoteBranch(repo middleware.Repository, branchName string, addBranch branch.Add) Checkout {
+	return checkOutRemoteBranch{
+		repo:       repo,
+		branchName: branchName,
+		addBranch:  addBranch,
+	}
+}
diff --git a/git/branch/checkout/checkout_remote_branch_test.go b/git/branch/checkout/checkout_remote_branch_test.go
new file mode 100644
index 0000000..b1e6968
--- /dev/null
+++ b/git/branch/checkout/checkout_remote_branch_test.go
@@ -0,0 +1,183 @@
+package checkout
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/branch"
+	branchMocks "github.com/neel1996/gitconvex/git/branch/mocks"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type CheckOutRemoteBranchTestSuite struct {
+	suite.Suite
+	repo                     middleware.Repository
+	mockController           *gomock.Controller
+	mockRepo                 *mocks.MockRepository
+	mockBranch               *mocks.MockBranch
+	mockCommit               *mocks.MockCommit
+	branchName               string
+	remoteBranchName         string
+	localBranchName          string
+	localBranchReferenceName string
+	branchValidation         branch.Validation
+	mockValidation           *branchMocks.MockValidation
+	addBranch                branch.Add
+	mockAddBranch            *branchMocks.MockAdd
+	checkOutRemoteBranch     Checkout
+}
+
+func TestCheckOutRemoteBranchTestSuite(t *testing.T) {
+	suite.Run(t, new(CheckOutRemoteBranchTestSuite))
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.branchName = "remotes/origin/master"
+	suite.remoteBranchName = "origin/master"
+	suite.localBranchName = "master"
+	suite.localBranchReferenceName = "refs/heads/master"
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockBranch = mocks.NewMockBranch(suite.mockController)
+	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
+	suite.mockValidation = branchMocks.NewMockValidation(suite.mockController)
+	suite.mockAddBranch = branchMocks.NewMockAdd(suite.mockController)
+	suite.branchValidation = branch.NewBranchFieldsValidation(suite.repo)
+	suite.addBranch = branch.NewAddBranchV2(suite.repo, suite.branchValidation)
+
+	suite.checkOutRemoteBranch = NewCheckoutRemoteBranch(suite.mockRepo, suite.branchName, suite.mockAddBranch)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TearDownTest() {
+	suite.mockController.Finish()
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenBranchIsValid_ShouldCheckoutLocalBranch() {
+	suite.checkOutRemoteBranch = NewCheckoutRemoteBranch(suite.repo, suite.branchName, suite.addBranch)
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.Nil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenBranchLookupFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenCommitLookupFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenFetchCommitTreeFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(nil, errors.New("TREE_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenCheckoutTreeFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(errors.New("TREE_CHECKOUT_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenLookupLocalBranch_ShouldAddNewLocalBranch() {
+	gitCommit := &git2go.Commit{}
+
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+	suite.mockCommit.EXPECT().GetGitCommit().Return(gitCommit)
+	suite.mockAddBranch.EXPECT().AddBranchV2(suite.branchName, false, gitCommit).Return(nil)
+	suite.mockRepo.EXPECT().SetHead(suite.localBranchReferenceName).Return(nil)
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.Nil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenLocalAddBranchFails_ShouldReturnError() {
+	gitCommit := &git2go.Commit{}
+
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+	suite.mockCommit.EXPECT().GetGitCommit().Return(gitCommit)
+	suite.mockAddBranch.EXPECT().AddBranchV2(suite.branchName, false, gitCommit).Return(errors.New("ADD_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenSetHeadFailsAfterAddingNewBranch_ShouldReturnError() {
+	gitCommit := &git2go.Commit{}
+
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+	suite.mockCommit.EXPECT().GetGitCommit().Return(gitCommit)
+	suite.mockAddBranch.EXPECT().AddBranchV2(suite.branchName, false, gitCommit).Return(nil)
+	suite.mockRepo.EXPECT().SetHead(suite.localBranchReferenceName).Return(errors.New("SET_HEAD_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenSetHeadFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.localBranchName, git2go.BranchLocal).Return(nil, nil)
+	suite.mockRepo.EXPECT().SetHead(suite.localBranchReferenceName).Return(errors.New("SET_HEAD_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
diff --git a/git/branch/git_branch_add.go b/git/branch/git_branch_add.go
index cf8086c..d850b27 100644
--- a/git/branch/git_branch_add.go
+++ b/git/branch/git_branch_add.go
@@ -1,5 +1,7 @@
 package branch
 
+//go:generate git/branch/git_branch_add.go
+
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
@@ -9,6 +11,7 @@ import (
 
 type Add interface {
 	AddBranch() error
+	AddBranchV2(branchName string, remoteSwitch bool, targetCommit *git2go.Commit) error
 }
 
 type addBranch struct {
@@ -19,6 +22,15 @@ type addBranch struct {
 	branchValidation Validation
 }
 
+func (a addBranch) AddBranchV2(branchName string, remoteSwitch bool, targetCommit *git2go.Commit) error {
+	// TODO: Make this function the default add branch once the consumers are migrated
+	a.branchName = branchName
+	a.remoteSwitch = remoteSwitch
+	a.targetCommit = targetCommit
+
+	return a.AddBranch()
+}
+
 func (a addBranch) AddBranch() error {
 	err := a.validateAddBranchFields()
 	if err != nil {
@@ -80,3 +92,10 @@ func NewAddBranch(repo middleware.Repository, branchName string, remoteSwitch bo
 		branchValidation: branchValidation,
 	}
 }
+
+func NewAddBranchV2(repo middleware.Repository, branchValidation Validation) Add {
+	return addBranch{
+		repo:             repo,
+		branchValidation: branchValidation,
+	}
+}
diff --git a/git/branch/mocks/git_branch_add.go b/git/branch/mocks/git_branch_add.go
new file mode 100644
index 0000000..ce1c990
--- /dev/null
+++ b/git/branch/mocks/git_branch_add.go
@@ -0,0 +1,63 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/branch/git_branch_add.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockAdd is a mock of Add interface.
+type MockAdd struct {
+	ctrl     *gomock.Controller
+	recorder *MockAddMockRecorder
+}
+
+// MockAddMockRecorder is the mock recorder for MockAdd.
+type MockAddMockRecorder struct {
+	mock *MockAdd
+}
+
+// NewMockAdd creates a new mock instance.
+func NewMockAdd(ctrl *gomock.Controller) *MockAdd {
+	mock := &MockAdd{ctrl: ctrl}
+	mock.recorder = &MockAddMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockAdd) EXPECT() *MockAddMockRecorder {
+	return m.recorder
+}
+
+// AddBranch mocks base method.
+func (m *MockAdd) AddBranch() error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "AddBranch")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// AddBranch indicates an expected call of AddBranch.
+func (mr *MockAddMockRecorder) AddBranch() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBranch", reflect.TypeOf((*MockAdd)(nil).AddBranch))
+}
+
+// AddBranchV2 mocks base method.
+func (m *MockAdd) AddBranchV2(branchName string, remoteSwitch bool, targetCommit *git.Commit) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "AddBranchV2", branchName, remoteSwitch, targetCommit)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// AddBranchV2 indicates an expected call of AddBranchV2.
+func (mr *MockAddMockRecorder) AddBranchV2(branchName, remoteSwitch, targetCommit interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBranchV2", reflect.TypeOf((*MockAdd)(nil).AddBranchV2), branchName, remoteSwitch, targetCommit)
+}
diff --git a/git/commit/mocks/mock_commit.go b/git/commit/mocks/mock_commit.go
deleted file mode 100644
index e6b0f84..0000000
--- a/git/commit/mocks/mock_commit.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Code generated by MockGen. DO NOT EDIT.
-// Source: git/middleware/commit.go
-
-// Package mocks is a generated GoMock package.
-package mocks
-
-import (
-	reflect "reflect"
-
-	gomock "github.com/golang/mock/gomock"
-	git "github.com/libgit2/git2go/v31"
-	middleware "github.com/neel1996/gitconvex/git/middleware"
-)
-
-// MockCommit is a mock of Commit interface.
-type MockCommit struct {
-	ctrl     *gomock.Controller
-	recorder *MockCommitMockRecorder
-}
-
-// MockCommitMockRecorder is the mock recorder for MockCommit.
-type MockCommitMockRecorder struct {
-	mock *MockCommit
-}
-
-// NewMockCommit creates a new mock instance.
-func NewMockCommit(ctrl *gomock.Controller) *MockCommit {
-	mock := &MockCommit{ctrl: ctrl}
-	mock.recorder = &MockCommitMockRecorder{mock}
-	return mock
-}
-
-// EXPECT returns an object that allows the caller to indicate expected use.
-func (m *MockCommit) EXPECT() *MockCommitMockRecorder {
-	return m.recorder
-}
-
-// Id mocks base method.
-func (m *MockCommit) Id() *git.Oid {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Id")
-	ret0, _ := ret[0].(*git.Oid)
-	return ret0
-}
-
-// Id indicates an expected call of Id.
-func (mr *MockCommitMockRecorder) Id() *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockCommit)(nil).Id))
-}
-
-// Parent mocks base method.
-func (m *MockCommit) Parent(arg0 uint) middleware.Commit {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Parent", arg0)
-	ret0, _ := ret[0].(middleware.Commit)
-	return ret0
-}
-
-// Parent indicates an expected call of Parent.
-func (mr *MockCommitMockRecorder) Parent(arg0 interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Parent", reflect.TypeOf((*MockCommit)(nil).Parent), arg0)
-}
-
-// ParentCount mocks base method.
-func (m *MockCommit) ParentCount() uint {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "ParentCount")
-	ret0, _ := ret[0].(uint)
-	return ret0
-}
-
-// ParentCount indicates an expected call of ParentCount.
-func (mr *MockCommitMockRecorder) ParentCount() *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParentCount", reflect.TypeOf((*MockCommit)(nil).ParentCount))
-}
-
-// Tree mocks base method.
-func (m *MockCommit) Tree() (*git.Tree, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "Tree")
-	ret0, _ := ret[0].(*git.Tree)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// Tree indicates an expected call of Tree.
-func (mr *MockCommitMockRecorder) Tree() *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Tree", reflect.TypeOf((*MockCommit)(nil).Tree))
-}
diff --git a/git/middleware/commit.go b/git/middleware/commit.go
index 6739a09..a8b99b5 100644
--- a/git/middleware/commit.go
+++ b/git/middleware/commit.go
@@ -7,12 +7,17 @@ type Commit interface {
 	Id() *git.Oid
 	Parent(uint) Commit
 	Tree() (*git.Tree, error)
+	GetGitCommit() *git.Commit
 }
 
 type commit struct {
 	gitCommit *git.Commit
 }
 
+func (c commit) GetGitCommit() *git.Commit {
+	return c.gitCommit
+}
+
 func (c commit) Tree() (*git.Tree, error) {
 	return c.gitCommit.Tree()
 }
diff --git a/mocks/mock_commit.go b/mocks/mock_commit.go
index e6b0f84..28a43c6 100644
--- a/mocks/mock_commit.go
+++ b/mocks/mock_commit.go
@@ -35,6 +35,20 @@ func (m *MockCommit) EXPECT() *MockCommitMockRecorder {
 	return m.recorder
 }
 
+// GetGitCommit mocks base method.
+func (m *MockCommit) GetGitCommit() *git.Commit {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetGitCommit")
+	ret0, _ := ret[0].(*git.Commit)
+	return ret0
+}
+
+// GetGitCommit indicates an expected call of GetGitCommit.
+func (mr *MockCommitMockRecorder) GetGitCommit() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGitCommit", reflect.TypeOf((*MockCommit)(nil).GetGitCommit))
+}
+
 // Id mocks base method.
 func (m *MockCommit) Id() *git.Oid {
 	m.ctrl.T.Helper()

From 1d295f1d7b230595f6129c772517d72f0c2ad62b Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 2 Sep 2021 23:57:13 +0530
Subject: [PATCH 109/148] replace checkout function with new factory method

---
 git/branch/branch.go                   |   3 +-
 git/branch/git_branch_checkout.go      | 186 -------------------------
 git/branch/git_branch_checkout_test.go |  93 -------------
 3 files changed, 2 insertions(+), 280 deletions(-)
 delete mode 100644 git/branch/git_branch_checkout.go
 delete mode 100644 git/branch/git_branch_checkout_test.go

diff --git a/git/branch/branch.go b/git/branch/branch.go
index 15fd00e..226df48 100644
--- a/git/branch/branch.go
+++ b/git/branch/branch.go
@@ -2,6 +2,7 @@ package branch
 
 import (
 	"errors"
+	"github.com/neel1996/gitconvex/git/branch/checkout"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
 )
@@ -17,7 +18,7 @@ type Branch interface {
 
 type Operation struct {
 	Add      Add
-	Checkout Checkout
+	Checkout checkout.Checkout
 	Compare  Compare
 	Delete   Delete
 	List     List
diff --git a/git/branch/git_branch_checkout.go b/git/branch/git_branch_checkout.go
deleted file mode 100644
index b024594..0000000
--- a/git/branch/git_branch_checkout.go
+++ /dev/null
@@ -1,186 +0,0 @@
-package branch
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"strings"
-)
-
-type Checkout interface {
-	CheckoutBranch() error
-}
-
-type branchCheckout struct {
-	repo       *git2go.Repository
-	branchName string
-}
-
-type validatedBranchDetails struct {
-	branchName          string
-	referenceBranchName string
-	remoteBranchName    string
-	isRemoteBranch      bool
-}
-
-func printAndReturnError(err error) error {
-	logger.Log(err.Error(), global.StatusError)
-	return err
-}
-
-// CheckoutBranch checks out the branchName received as argument
-func (b branchCheckout) CheckoutBranch() error {
-	err := b.validateBranchFields()
-	if err != nil {
-		return err
-	}
-
-	branchDetails := b.validateAndSetBranchDetails()
-
-	if branchDetails.isRemoteBranch {
-		return b.checkoutRemoteBranch(branchDetails)
-	}
-
-	return b.checkoutLocalBranch(branchDetails)
-}
-
-func (b branchCheckout) validateBranchFields() error {
-	if err := NewBranchFieldsValidation(b.repo, b.branchName).ValidateBranchFields(); err != nil {
-		logger.Log(err.Error(), global.StatusError)
-		return err
-	}
-	return nil
-}
-
-func (b branchCheckout) checkoutRemoteBranch(branchDetails validatedBranchDetails) error {
-	branchName := b.branchName
-	repo := b.repo
-
-	logger.Log(fmt.Sprintf("Branch - %s is a remote branch. Trying with intermediate remote fetch!", branchName), global.StatusWarning)
-
-	remoteBranch, remoteBranchErr := repo.LookupBranch(branchDetails.remoteBranchName, git2go.BranchRemote)
-	if remoteBranchErr != nil {
-		return printAndReturnError(remoteBranchErr)
-	}
-
-	remoteHead := remoteBranch.Target()
-	remoteCommit, remoteCommitErr := repo.LookupCommit(remoteHead)
-	if remoteCommitErr != nil {
-		return printAndReturnError(remoteCommitErr)
-
-	}
-
-	remoteTree, remoteTreeErr := remoteCommit.Tree()
-	if remoteTreeErr != nil {
-		return printAndReturnError(remoteTreeErr)
-	}
-
-	if checkoutErr := repo.CheckoutTree(remoteTree, &git2go.CheckoutOptions{Strategy: git2go.CheckoutSafe}); checkoutErr != nil {
-		return printAndReturnError(checkoutErr)
-	}
-
-	_, localLookupErr := repo.LookupBranch(branchName, git2go.BranchLocal)
-	if localLookupErr != nil {
-		logger.Log(localLookupErr.Error(), global.StatusError)
-		return addAndCheckoutNewBranch(repo, branchName, remoteCommit, branchDetails)
-	}
-
-	if err := repo.SetHead(branchDetails.referenceBranchName); err != nil {
-		return printAndReturnError(err)
-	}
-
-	logger.Log(fmt.Sprintf("Remote branch %v has been checked out", branchDetails.remoteBranchName), global.StatusInfo)
-	return nil
-}
-
-func (b branchCheckout) checkoutLocalBranch(branchDetails validatedBranchDetails) error {
-	repo := b.repo
-	branchName := b.branchName
-
-	branch, branchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
-	if branchErr != nil {
-		fmt.Println("Lookup error")
-		return printAndReturnError(branchErr)
-	}
-
-	lookupCommit, lookupCommitErr := repo.LookupCommit(branch.Target())
-	if lookupCommit == nil {
-		fmt.Println("Lookup commit error")
-		return printAndReturnError(lookupCommitErr)
-	}
-
-	tree, treeErr := lookupCommit.Tree()
-	if treeErr != nil {
-		fmt.Println("Lookup tree error")
-		return printAndReturnError(treeErr)
-	}
-
-	checkoutErr := repo.CheckoutTree(tree, &git2go.CheckoutOptions{
-		Strategy:       git2go.CheckoutSafe,
-		DisableFilters: false,
-	})
-
-	if checkoutErr != nil {
-		return printAndReturnError(checkoutErr)
-	}
-
-	err := repo.SetHead(branchDetails.referenceBranchName)
-	if err != nil {
-		return printAndReturnError(err)
-	}
-
-	logger.Log(fmt.Sprintf("Local branch %v has been checked out", b.branchName), global.StatusInfo)
-	return nil
-}
-
-func addAndCheckoutNewBranch(repo *git2go.Repository, branchName string, remoteCommit *git2go.Commit, branchDetails validatedBranchDetails) error {
-	addBranch := NewAddBranch(repo, branchName, false, remoteCommit)
-
-	branchAddError := addBranch.AddBranch()
-	if branchAddError != nil {
-		return branchAddError
-	}
-
-	if err := repo.SetHead(branchDetails.referenceBranchName); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func (b branchCheckout) validateAndSetBranchDetails() validatedBranchDetails {
-	var (
-		branchName          = b.branchName
-		referenceBranchName string
-		remoteBranchName    string
-		isRemoteBranch      bool
-	)
-
-	if strings.Contains(branchName, "remotes/") {
-		referenceBranchName = "refs/heads/" + splitAndReturnBranchName("/", branchName)
-		remoteBranchName = splitAndReturnBranchName("remotes/", branchName)
-		branchName = splitAndReturnBranchName("/", branchName)
-		isRemoteBranch = true
-	} else {
-		referenceBranchName = "refs/heads/" + branchName
-	}
-
-	return validatedBranchDetails{
-		branchName:          branchName,
-		referenceBranchName: referenceBranchName,
-		remoteBranchName:    remoteBranchName,
-		isRemoteBranch:      isRemoteBranch,
-	}
-}
-
-func splitAndReturnBranchName(delimiter string, branchName string) string {
-	splitString := strings.Split(branchName, delimiter)
-	return splitString[len(splitString)-1]
-}
-
-func NewBranchCheckout(repo *git2go.Repository, branchName string) Checkout {
-	return branchCheckout{
-		repo:       repo,
-		branchName: branchName,
-	}
-}
diff --git a/git/branch/git_branch_checkout_test.go b/git/branch/git_branch_checkout_test.go
deleted file mode 100644
index 97d2866..0000000
--- a/git/branch/git_branch_checkout_test.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package branch
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/stretchr/testify/suite"
-	"os"
-	"path/filepath"
-	"testing"
-)
-
-type BranchCheckoutTestSuite struct {
-	suite.Suite
-	branchName     string
-	checkoutBranch Checkout
-	repo           *git2go.Repository
-	noHeadRepo     *git2go.Repository
-}
-
-func TestBranchCheckoutTestSuite(t *testing.T) {
-	suite.Run(t, new(BranchCheckoutTestSuite))
-}
-
-func (suite *BranchCheckoutTestSuite) SetupSuite() {
-	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	if err != nil {
-		fmt.Println(err)
-	}
-
-	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
-	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
-
-	suite.repo = r
-	suite.noHeadRepo = noHeadRepo
-	suite.branchName = "test_checkout"
-	addErr := NewAddBranch(suite.repo, suite.branchName, false, nil).AddBranch()
-	if addErr != nil {
-		fmt.Println(addErr)
-	}
-	suite.checkoutBranch = NewBranchCheckout(suite.repo, suite.branchName)
-}
-
-func (suite *BranchCheckoutTestSuite) TearDownSuite() {
-	suite.branchName = "master"
-	err := suite.checkoutBranch.CheckoutBranch()
-	if err != nil {
-		return
-	}
-	_ = NewDeleteBranch(suite.repo, suite.branchName).DeleteBranch()
-}
-
-func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenBranchIsCheckedOut_ShouldReturnNil() {
-	err := suite.checkoutBranch.CheckoutBranch()
-
-	suite.Nil(err)
-}
-
-func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenRemoteBranchIsCheckedOut_ShouldReturnNil() {
-	suite.checkoutBranch = NewBranchCheckout(suite.repo, "remotes/origin/master")
-	err := suite.checkoutBranch.CheckoutBranch()
-
-	suite.Nil(err)
-}
-
-func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenRepoIsNil_ShouldReturnError() {
-	suite.checkoutBranch = NewBranchCheckout(nil, "test_branch")
-	err := suite.checkoutBranch.CheckoutBranch()
-
-	suite.NotNil(err)
-	suite.Equal("repo is nil", err.Error())
-}
-
-func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenBranchNameIsEmpty_ShouldReturnError() {
-	suite.checkoutBranch = NewBranchCheckout(suite.repo, "")
-	err := suite.checkoutBranch.CheckoutBranch()
-
-	suite.NotNil(err)
-	suite.Equal("branch name is empty", err.Error())
-}
-
-func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenRepoHasNoHead_ShouldReturnError() {
-	suite.checkoutBranch = NewBranchCheckout(suite.noHeadRepo, suite.branchName)
-	err := suite.checkoutBranch.CheckoutBranch()
-
-	suite.NotNil(err)
-}
-
-func (suite *BranchCheckoutTestSuite) TestCheckoutBranch_WhenNonExistingBranchIsSelected_ShouldReturnError() {
-	suite.checkoutBranch = NewBranchCheckout(suite.repo, "no_exists")
-	err := suite.checkoutBranch.CheckoutBranch()
-
-	suite.NotNil(err)
-}

From d3f90948be2d40ee39bed082b7a2519e9eb97ba9 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 4 Sep 2021 22:44:42 +0530
Subject: [PATCH 110/148] add new validator package for common validation
 functions

---
 validator/branch_validator.go      | 22 +++++++++++++++
 validator/branch_validator_test.go | 38 ++++++++++++++++++++++++++
 validator/repo_validator.go        | 18 ++++++++++++
 validator/repo_validator_test.go   | 44 ++++++++++++++++++++++++++++++
 validator/validaor.go              |  9 ++++++
 validator/validation_errors.go     | 16 +++++++++++
 6 files changed, 147 insertions(+)
 create mode 100644 validator/branch_validator.go
 create mode 100644 validator/branch_validator_test.go
 create mode 100644 validator/repo_validator.go
 create mode 100644 validator/repo_validator_test.go
 create mode 100644 validator/validaor.go
 create mode 100644 validator/validation_errors.go

diff --git a/validator/branch_validator.go b/validator/branch_validator.go
new file mode 100644
index 0000000..c0be454
--- /dev/null
+++ b/validator/branch_validator.go
@@ -0,0 +1,22 @@
+package validator
+
+type branchValidator struct {
+}
+
+func (v branchValidator) ValidateWithFields(branchNames ...string) error {
+	if len(branchNames) == 0 {
+		return EmptyBranchName
+	}
+
+	for _, branchName := range branchNames {
+		if branchName == "" {
+			return EmptyBranchName
+		}
+	}
+
+	return nil
+}
+
+func NewBranchValidator() ValidatorWithStringFields {
+	return branchValidator{}
+}
diff --git a/validator/branch_validator_test.go b/validator/branch_validator_test.go
new file mode 100644
index 0000000..bc3fef7
--- /dev/null
+++ b/validator/branch_validator_test.go
@@ -0,0 +1,38 @@
+package validator
+
+import (
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type BranchValidatorTestSuite struct {
+	suite.Suite
+	branchValidator ValidatorWithStringFields
+}
+
+func TestBranchValidatorTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchValidatorTestSuite))
+}
+
+func (suite *BranchValidatorTestSuite) SetupTest() {
+	suite.branchValidator = NewBranchValidator()
+}
+
+func (suite *BranchValidatorTestSuite) TestValidate_WhenPassedBranchIsValid_ShouldReturnNil() {
+	err := suite.branchValidator.ValidateWithFields("test_1")
+
+	suite.Nil(err)
+}
+
+func (suite *BranchValidatorTestSuite) TestValidate_WhenPassedBranchesAreValid_ShouldReturnNil() {
+	err := suite.branchValidator.ValidateWithFields("test_1", "test_2")
+
+	suite.Nil(err)
+}
+
+func (suite *BranchValidatorTestSuite) TestValidate_WhenPassedEmptyStringIsPassed_ShouldReturnEmptybranchError() {
+	err := suite.branchValidator.ValidateWithFields()
+
+	suite.NotNil(err)
+	suite.Equal(EmptyBranchName, err)
+}
diff --git a/validator/repo_validator.go b/validator/repo_validator.go
new file mode 100644
index 0000000..9caa3e9
--- /dev/null
+++ b/validator/repo_validator.go
@@ -0,0 +1,18 @@
+package validator
+
+import "github.com/neel1996/gitconvex/git/middleware"
+
+type repoValidator struct {
+	repo middleware.Repository
+}
+
+func (v repoValidator) Validate() error {
+	if v.repo == nil {
+		return NilRepoError
+	}
+	return nil
+}
+
+func NewRepoValidator(repo middleware.Repository) Validator {
+	return repoValidator{repo: repo}
+}
diff --git a/validator/repo_validator_test.go b/validator/repo_validator_test.go
new file mode 100644
index 0000000..d65b1e8
--- /dev/null
+++ b/validator/repo_validator_test.go
@@ -0,0 +1,44 @@
+package validator
+
+import (
+	"github.com/golang/mock/gomock"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type RepoValidatorTestSuite struct {
+	suite.Suite
+	mockController *gomock.Controller
+	mockRepo       *mocks.MockRepository
+	repoValidator  Validator
+}
+
+func TestRepoValidatorTestSuite(t *testing.T) {
+	suite.Run(t, new(RepoValidatorTestSuite))
+}
+
+func (suite *RepoValidatorTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.repoValidator = NewRepoValidator(suite.mockRepo)
+}
+
+func (suite *RepoValidatorTestSuite) TearDownTest() {
+	suite.mockController.Finish()
+}
+
+func (suite *RepoValidatorTestSuite) TestValidate_WhenRepoIsNotNil_ShouldReturnNil() {
+	err := suite.repoValidator.Validate()
+
+	suite.Nil(err)
+}
+
+func (suite *RepoValidatorTestSuite) TestValidate_WhenRepoIsNil_ShouldReturnRepoNilError() {
+	suite.repoValidator = NewRepoValidator(nil)
+
+	err := suite.repoValidator.Validate()
+
+	suite.NotNil(err)
+	suite.Equal(NilRepoError, err)
+}
diff --git a/validator/validaor.go b/validator/validaor.go
new file mode 100644
index 0000000..63893c4
--- /dev/null
+++ b/validator/validaor.go
@@ -0,0 +1,9 @@
+package validator
+
+type Validator interface {
+	Validate() error
+}
+
+type ValidatorWithStringFields interface {
+	ValidateWithFields(fields ...string) error
+}
diff --git a/validator/validation_errors.go b/validator/validation_errors.go
new file mode 100644
index 0000000..e8493ac
--- /dev/null
+++ b/validator/validation_errors.go
@@ -0,0 +1,16 @@
+package validator
+
+type Error struct {
+	error
+	ErrorCode   string
+	ErrorString string
+}
+
+var (
+	NilRepoError    = Error{ErrorCode: "REPO_NIL_ERROR", ErrorString: "Repo is nil"}
+	EmptyBranchName = Error{ErrorCode: "EMPTY_BRANCH_NAME", ErrorString: "Branch name is empty"}
+)
+
+func (e Error) Error() string {
+	return e.ErrorString
+}

From 7817562d727e9c0049d5a550417c5cd0bb888ec5 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 5 Sep 2021 23:57:00 +0530
Subject: [PATCH 111/148] add new test util function to add a new local branch

---
 test_utils/add_test_branch.go | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
 create mode 100644 test_utils/add_test_branch.go

diff --git a/test_utils/add_test_branch.go b/test_utils/add_test_branch.go
new file mode 100644
index 0000000..0b31760
--- /dev/null
+++ b/test_utils/add_test_branch.go
@@ -0,0 +1,14 @@
+package test_utils
+
+import (
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/validator"
+)
+
+func AddNewTestLocalBranch(repo middleware.Repository, branchName string) {
+	_ = branch.NewAddBranch(
+		repo,
+		validator.NewBranchValidator(),
+	).AddBranch(branchName, false, nil)
+}

From 2ee9a7f89ad91a6073c701ba0723271abaf5a1c6 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 6 Sep 2021 22:58:27 +0530
Subject: [PATCH 112/148] add new test util function to checkout a new local
 branch

---
 test_utils/checkout_test_local_branch.go | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 test_utils/checkout_test_local_branch.go

diff --git a/test_utils/checkout_test_local_branch.go b/test_utils/checkout_test_local_branch.go
new file mode 100644
index 0000000..cb948af
--- /dev/null
+++ b/test_utils/checkout_test_local_branch.go
@@ -0,0 +1,15 @@
+package test_utils
+
+import (
+	"github.com/neel1996/gitconvex/git/branch/checkout"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"log"
+)
+
+func CheckoutTestLocalBranch(repo middleware.Repository, branchName string) {
+	err := checkout.NewCheckOutLocalBranch(repo, branchName).CheckoutBranch()
+	if err != nil {
+		log.Println(err)
+		return
+	}
+}

From e226fa209673ecdab5780cb2d21590c4206bfe1e Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 7 Sep 2021 00:12:07 +0530
Subject: [PATCH 113/148] replace branch validation logic with new validator
 function

---
 git/branch/git_branch_add.go      | 27 +++++--------------
 git/branch/git_branch_add_test.go | 44 +++++++++++++------------------
 2 files changed, 25 insertions(+), 46 deletions(-)

diff --git a/git/branch/git_branch_add.go b/git/branch/git_branch_add.go
index d850b27..f24e543 100644
--- a/git/branch/git_branch_add.go
+++ b/git/branch/git_branch_add.go
@@ -7,11 +7,11 @@ import (
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/validator"
 )
 
 type Add interface {
-	AddBranch() error
-	AddBranchV2(branchName string, remoteSwitch bool, targetCommit *git2go.Commit) error
+	AddBranch(branchName string, remoteSwitch bool, targetCommit *git2go.Commit) error
 }
 
 type addBranch struct {
@@ -19,19 +19,14 @@ type addBranch struct {
 	branchName       string
 	remoteSwitch     bool
 	targetCommit     *git2go.Commit
-	branchValidation Validation
+	branchValidation validator.ValidatorWithStringFields
 }
 
-func (a addBranch) AddBranchV2(branchName string, remoteSwitch bool, targetCommit *git2go.Commit) error {
-	// TODO: Make this function the default add branch once the consumers are migrated
+func (a addBranch) AddBranch(branchName string, remoteSwitch bool, targetCommit *git2go.Commit) error {
 	a.branchName = branchName
 	a.remoteSwitch = remoteSwitch
 	a.targetCommit = targetCommit
 
-	return a.AddBranch()
-}
-
-func (a addBranch) AddBranch() error {
 	err := a.validateAddBranchFields()
 	if err != nil {
 		logger.Log(err.Error(), global.StatusError)
@@ -63,7 +58,7 @@ func (a addBranch) AddBranch() error {
 }
 
 func (a addBranch) validateAddBranchFields() error {
-	err := a.branchValidation.ValidateBranchFields(a.branchName)
+	err := a.branchValidation.ValidateWithFields(a.branchName)
 	if err != nil {
 		return err
 	}
@@ -83,17 +78,7 @@ func (a addBranch) validateTargetCommit(targetCommit *git2go.Commit, repo middle
 	return headCommit, nil
 }
 
-func NewAddBranch(repo middleware.Repository, branchName string, remoteSwitch bool, targetCommit *git2go.Commit, branchValidation Validation) Add {
-	return addBranch{
-		repo:             repo,
-		branchName:       branchName,
-		remoteSwitch:     remoteSwitch,
-		targetCommit:     targetCommit,
-		branchValidation: branchValidation,
-	}
-}
-
-func NewAddBranchV2(repo middleware.Repository, branchValidation Validation) Add {
+func NewAddBranch(repo middleware.Repository, branchValidation validator.ValidatorWithStringFields) Add {
 	return addBranch{
 		repo:             repo,
 		branchValidation: branchValidation,
diff --git a/git/branch/git_branch_add_test.go b/git/branch/git_branch_add_test.go
index c312490..a2bd60e 100644
--- a/git/branch/git_branch_add_test.go
+++ b/git/branch/git_branch_add_test.go
@@ -6,10 +6,10 @@ import (
 	"github.com/golang/mock/gomock"
 	"github.com/google/uuid"
 	git2go "github.com/libgit2/git2go/v31"
-	branchMocks "github.com/neel1996/gitconvex/git/branch/mocks"
-	commitMocks "github.com/neel1996/gitconvex/git/commit/mocks"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/mocks"
+	"github.com/neel1996/gitconvex/validator"
+	validatorMock "github.com/neel1996/gitconvex/validator/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
 	"testing"
@@ -21,10 +21,10 @@ type BranchAddTestSuite struct {
 	mockController       *gomock.Controller
 	mockRepo             *mocks.MockRepository
 	mockReference        *mocks.MockReference
-	mockBranchValidation *branchMocks.MockValidation
-	mockCommit           *commitMocks.MockCommit
+	mockBranchValidation *validatorMock.MockValidatorWithStringFields
+	mockCommit           *mocks.MockCommit
 	branchName           string
-	branchValidation     Validation
+	branchValidation     validator.ValidatorWithStringFields
 	branchAdd            Add
 }
 
@@ -43,21 +43,15 @@ func (suite *BranchAddTestSuite) SetupTest() {
 	}
 
 	suite.repo = middleware.NewRepository(r)
-	suite.branchValidation = NewBranchFieldsValidation(suite.repo)
+	suite.branchValidation = validator.NewBranchValidator()
 
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
 	suite.mockReference = mocks.NewMockReference(suite.mockController)
-	suite.mockCommit = commitMocks.NewMockCommit(suite.mockController)
-	suite.mockBranchValidation = branchMocks.NewMockValidation(suite.mockController)
+	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
+	suite.mockBranchValidation = validatorMock.NewMockValidatorWithStringFields(suite.mockController)
 
-	suite.branchAdd = NewAddBranch(
-		suite.mockRepo,
-		suite.branchName,
-		false,
-		nil,
-		suite.mockBranchValidation,
-	)
+	suite.branchAdd = NewAddBranch(suite.mockRepo, suite.mockBranchValidation)
 }
 
 func (suite *BranchAddTestSuite) TearDownSuite() {
@@ -67,26 +61,26 @@ func (suite *BranchAddTestSuite) TearDownSuite() {
 }
 
 func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchAdditionSucceeds_ShouldReturnNil() {
-	suite.branchAdd = NewAddBranch(suite.repo, suite.branchName, false, nil, suite.branchValidation)
+	suite.branchAdd = NewAddBranch(suite.repo, suite.branchValidation)
 
-	branchAddError := suite.branchAdd.AddBranch()
+	branchAddError := suite.branchAdd.AddBranch(suite.branchName, false, nil)
 
 	suite.Nil(branchAddError)
 }
 
 func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchValidationFails_ShouldReturnError() {
-	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.branchName).Return(EmptyBranchNameError)
+	suite.mockBranchValidation.EXPECT().ValidateWithFields("").Return(EmptyBranchNameError)
 
-	branchAddError := suite.branchAdd.AddBranch()
+	branchAddError := suite.branchAdd.AddBranch("", false, nil)
 
 	suite.NotNil(branchAddError)
 }
 
 func (suite *BranchAddTestSuite) TestAddBranch_WhenHeadIsNil_ShouldReturnError() {
-	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.branchName).Return(nil)
+	suite.mockBranchValidation.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
 	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("HEAD_ERROR"))
 
-	branchAddError := suite.branchAdd.AddBranch()
+	branchAddError := suite.branchAdd.AddBranch(suite.branchName, false, nil)
 
 	suite.NotNil(branchAddError)
 }
@@ -94,12 +88,12 @@ func (suite *BranchAddTestSuite) TestAddBranch_WhenHeadIsNil_ShouldReturnError()
 func (suite *BranchAddTestSuite) TestAddBranch_WhenHeadCommitLookupFails_ShouldReturnError() {
 	oid, _ := git2go.NewOid("0608f9c6c97f386d1fa3948f3b8a61ae1cdb5621")
 
-	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.branchName).Return(nil)
+	suite.mockBranchValidation.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
 	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
 	suite.mockReference.EXPECT().Target().Return(oid)
 	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, errors.New("LOOKUP_ERROR"))
 
-	branchAddError := suite.branchAdd.AddBranch()
+	branchAddError := suite.branchAdd.AddBranch(suite.branchName, false, nil)
 
 	suite.NotNil(branchAddError)
 }
@@ -108,7 +102,7 @@ func (suite *BranchAddTestSuite) TestAddBranch_WhenCreateBranchFails_ShouldRetur
 	oid, _ := git2go.NewOid("0608f9c6c97f386d1fa3948f3b8a61ae1cdb5621")
 	commit := &git2go.Commit{}
 
-	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.branchName).Return(nil)
+	suite.mockBranchValidation.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
 	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
 	suite.mockReference.EXPECT().Target().Return(oid)
 	suite.mockRepo.EXPECT().LookupCommit(oid).Return(commit, nil)
@@ -118,7 +112,7 @@ func (suite *BranchAddTestSuite) TestAddBranch_WhenCreateBranchFails_ShouldRetur
 		false,
 	).Return(nil, errors.New("BRANCH_CREATE_ERROR"))
 
-	branchAddError := suite.branchAdd.AddBranch()
+	branchAddError := suite.branchAdd.AddBranch(suite.branchName, false, nil)
 
 	suite.NotNil(branchAddError)
 }

From 1f041833954a7c0eec8a6ed6258f9af19bb2eeae Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 8 Sep 2021 23:23:16 +0530
Subject: [PATCH 114/148] update checkout factory with new validator functions

---
 git/branch/checkout/checkout_factory.go      | 29 ++++++-----
 git/branch/checkout/checkout_factory_test.go | 52 +++++++++++++-------
 2 files changed, 50 insertions(+), 31 deletions(-)

diff --git a/git/branch/checkout/checkout_factory.go b/git/branch/checkout/checkout_factory.go
index cecbb2c..483f1b4 100644
--- a/git/branch/checkout/checkout_factory.go
+++ b/git/branch/checkout/checkout_factory.go
@@ -2,9 +2,9 @@ package checkout
 
 import (
 	"fmt"
-	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/validator"
 	"strings"
 )
 
@@ -13,21 +13,25 @@ type Factory interface {
 }
 
 type factory struct {
-	repo             middleware.Repository
-	branchName       string
-	branchValidation branch.Validation
+	repo            middleware.Repository
+	branchName      string
+	repoValidator   validator.Validator
+	branchValidator validator.ValidatorWithStringFields
 }
 
 func (f factory) GetCheckoutAction() Checkout {
 	logger.Log(fmt.Sprintf("Received branch %s", f.branchName), global.StatusInfo)
+	if repoValidationErr := f.repoValidator.Validate(); repoValidationErr != nil {
+		logger.Log(repoValidationErr.Error(), global.StatusError)
+		return nil
+	}
+
 	if validationErr := f.validateBranchFields(); validationErr != nil {
 		return nil
 	}
 
 	if strings.Contains(f.branchName, "remotes/") {
-		addBranch := branch.NewAddBranchV2(f.repo, f.branchValidation)
-
-		return NewCheckoutRemoteBranch(f.repo, f.branchName, addBranch)
+		return NewCheckoutRemoteBranch(f.repo, f.branchName, nil)
 	} else {
 		return NewCheckOutLocalBranch(f.repo, f.branchName)
 	}
@@ -36,17 +40,18 @@ func (f factory) GetCheckoutAction() Checkout {
 func (f factory) validateBranchFields() error {
 	logger.Log("Validating branch fields before checkout", global.StatusInfo)
 
-	if err := f.branchValidation.ValidateBranchFields(f.branchName); err != nil {
+	if err := f.branchValidator.ValidateWithFields(f.branchName); err != nil {
 		logger.Log(err.Error(), global.StatusError)
 		return err
 	}
 	return nil
 }
 
-func NewCheckoutFactory(repo middleware.Repository, branchName string, branchValidation branch.Validation) Factory {
+func NewCheckoutFactory(repo middleware.Repository, branchName string, repoValidator validator.Validator, branchValidator validator.ValidatorWithStringFields) Factory {
 	return factory{
-		repo:             repo,
-		branchName:       branchName,
-		branchValidation: branchValidation,
+		repo:            repo,
+		branchName:      branchName,
+		repoValidator:   repoValidator,
+		branchValidator: branchValidator,
 	}
 }
diff --git a/git/branch/checkout/checkout_factory_test.go b/git/branch/checkout/checkout_factory_test.go
index bd622df..1521336 100644
--- a/git/branch/checkout/checkout_factory_test.go
+++ b/git/branch/checkout/checkout_factory_test.go
@@ -1,25 +1,26 @@
 package checkout
 
 import (
+	"errors"
 	"github.com/golang/mock/gomock"
-	"github.com/neel1996/gitconvex/git/branch"
-	branchMocks "github.com/neel1996/gitconvex/git/branch/mocks"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/mocks"
+	"github.com/neel1996/gitconvex/validator"
+	validatorMock "github.com/neel1996/gitconvex/validator/mocks"
 	"github.com/stretchr/testify/suite"
 	"testing"
 )
 
 type CheckoutFactoryTestSuite struct {
 	suite.Suite
-	repo                 middleware.Repository
-	branchName           string
-	remoteBranchName     string
-	addBranch            branch.Add
-	mockController       *gomock.Controller
-	mockRepo             *mocks.MockRepository
-	mockBranchValidation *branchMocks.MockValidation
-	checkoutFactory      Factory
+	repo                middleware.Repository
+	branchName          string
+	remoteBranchName    string
+	mockController      *gomock.Controller
+	mockRepo            *mocks.MockRepository
+	mockBranchValidator *validatorMock.MockValidatorWithStringFields
+	mockRepoValidator   *validatorMock.MockValidator
+	checkoutFactory     Factory
 }
 
 func TestCheckoutFactoryTestSuite(t *testing.T) {
@@ -29,10 +30,10 @@ func TestCheckoutFactoryTestSuite(t *testing.T) {
 func (suite *CheckoutFactoryTestSuite) SetupTest() {
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.mockBranchValidation = branchMocks.NewMockValidation(suite.mockController)
+	suite.mockBranchValidator = validatorMock.NewMockValidatorWithStringFields(suite.mockController)
+	suite.mockRepoValidator = validatorMock.NewMockValidator(suite.mockController)
 	suite.branchName = "test_branch"
 	suite.remoteBranchName = "remotes/origin/test_branch"
-	suite.addBranch = branch.NewAddBranchV2(suite.mockRepo, suite.mockBranchValidation)
 }
 
 func (suite *CheckoutFactoryTestSuite) TearDownTest() {
@@ -40,9 +41,10 @@ func (suite *CheckoutFactoryTestSuite) TearDownTest() {
 }
 
 func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsLocal_ShouldReturnLocalCheckoutAction() {
-	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.branchName, suite.mockBranchValidation)
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.branchName, suite.mockRepoValidator, suite.mockBranchValidator)
 
-	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.branchName).Return(nil)
+	suite.mockRepoValidator.EXPECT().Validate().Return(nil)
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
 
 	wantAction := NewCheckOutLocalBranch(suite.mockRepo, suite.branchName)
 	gotAction := suite.checkoutFactory.GetCheckoutAction()
@@ -51,20 +53,32 @@ func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsLocal_S
 }
 
 func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsRemote_ShouldReturnRemoteCheckoutAction() {
-	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.remoteBranchName, suite.mockBranchValidation)
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.remoteBranchName, suite.mockRepoValidator, suite.mockBranchValidator)
 
-	suite.mockBranchValidation.EXPECT().ValidateBranchFields(suite.remoteBranchName).Return(nil)
+	suite.mockRepoValidator.EXPECT().Validate().Return(nil)
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.remoteBranchName).Return(nil)
 
-	wantAction := NewCheckoutRemoteBranch(suite.mockRepo, suite.remoteBranchName, suite.addBranch)
+	wantAction := NewCheckoutRemoteBranch(suite.mockRepo, suite.remoteBranchName, nil)
 	gotAction := suite.checkoutFactory.GetCheckoutAction()
 
 	suite.Equal(wantAction, gotAction)
 }
 
+func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenRepoValidationFails_ShouldReturnNil() {
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, "", suite.mockRepoValidator, suite.mockBranchValidator)
+
+	suite.mockRepoValidator.EXPECT().Validate().Return(validator.NilRepoError)
+
+	gotAction := suite.checkoutFactory.GetCheckoutAction()
+
+	suite.Nil(gotAction)
+}
+
 func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchValidationFails_ShouldReturnNil() {
-	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, "", suite.mockBranchValidation)
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, "", suite.mockRepoValidator, suite.mockBranchValidator)
 
-	suite.mockBranchValidation.EXPECT().ValidateBranchFields("").Return(branch.EmptyBranchNameError)
+	suite.mockRepoValidator.EXPECT().Validate().Return(nil)
+	suite.mockBranchValidator.EXPECT().ValidateWithFields("").Return(errors.New("VALIDATE_ERROR"))
 
 	gotAction := suite.checkoutFactory.GetCheckoutAction()
 

From 8958ae81fd9f6c904e969e5153b7592c643f7126 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 8 Sep 2021 23:24:58 +0530
Subject: [PATCH 115/148] update add branch in checkout test with new test
 utils to resolve cyclic dependency

---
 git/branch/checkout/checkout_local_branch_test.go | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/git/branch/checkout/checkout_local_branch_test.go b/git/branch/checkout/checkout_local_branch_test.go
index edb4ed9..fd3b9c9 100644
--- a/git/branch/checkout/checkout_local_branch_test.go
+++ b/git/branch/checkout/checkout_local_branch_test.go
@@ -8,6 +8,7 @@ import (
 	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/mocks"
+	"github.com/neel1996/gitconvex/test_utils"
 	"github.com/stretchr/testify/suite"
 	"os"
 	"testing"
@@ -37,13 +38,7 @@ func (suite *CheckOutLocalBranchTestSuite) SetupSuite() {
 	suite.repo = middleware.NewRepository(r)
 	suite.branchName = "test_checkout"
 
-	_ = branch.NewAddBranch(
-		suite.repo,
-		suite.branchName,
-		false,
-		nil,
-		branch.NewBranchFieldsValidation(suite.repo),
-	).AddBranch()
+	test_utils.AddNewTestLocalBranch(suite.repo, suite.branchName)
 }
 
 func (suite *CheckOutLocalBranchTestSuite) TearDownSuite() {

From e19a289fd4329eadb82c259141729b53968c4a8d Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 9 Sep 2021 00:51:05 +0530
Subject: [PATCH 116/148] include add branch as a dependency to remote branch
 checkout api

---
 git/branch/checkout/checkout_remote_branch.go |  2 +-
 .../checkout/checkout_remote_branch_test.go   | 19 ++++++++++---------
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/git/branch/checkout/checkout_remote_branch.go b/git/branch/checkout/checkout_remote_branch.go
index c336acb..3b64fc0 100644
--- a/git/branch/checkout/checkout_remote_branch.go
+++ b/git/branch/checkout/checkout_remote_branch.go
@@ -64,7 +64,7 @@ func (c checkOutRemoteBranch) CheckoutBranch() error {
 func (c checkOutRemoteBranch) addAndCheckoutNewBranch(remoteCommit *git2go.Commit, referenceBranchName string) error {
 	logger.Log("Adding local branch for remote reference", global.StatusInfo)
 
-	branchAddError := c.addBranch.AddBranchV2(c.branchName, false, remoteCommit)
+	branchAddError := c.addBranch.AddBranch(c.branchName, false, remoteCommit)
 	if branchAddError != nil {
 		logger.Log("Error while adding branch "+branchAddError.Error(), global.StatusError)
 		return branchAddError
diff --git a/git/branch/checkout/checkout_remote_branch_test.go b/git/branch/checkout/checkout_remote_branch_test.go
index b1e6968..3afa5c1 100644
--- a/git/branch/checkout/checkout_remote_branch_test.go
+++ b/git/branch/checkout/checkout_remote_branch_test.go
@@ -9,6 +9,7 @@ import (
 	branchMocks "github.com/neel1996/gitconvex/git/branch/mocks"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/mocks"
+	"github.com/neel1996/gitconvex/validator"
 	"github.com/stretchr/testify/suite"
 	"os"
 	"testing"
@@ -25,9 +26,9 @@ type CheckOutRemoteBranchTestSuite struct {
 	remoteBranchName         string
 	localBranchName          string
 	localBranchReferenceName string
-	branchValidation         branch.Validation
-	mockValidation           *branchMocks.MockValidation
+	branchValidation         validator.ValidatorWithStringFields
 	addBranch                branch.Add
+	mockValidation           *branchMocks.MockValidation
 	mockAddBranch            *branchMocks.MockAdd
 	checkOutRemoteBranch     Checkout
 }
@@ -56,8 +57,8 @@ func (suite *CheckOutRemoteBranchTestSuite) SetupTest() {
 	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
 	suite.mockValidation = branchMocks.NewMockValidation(suite.mockController)
 	suite.mockAddBranch = branchMocks.NewMockAdd(suite.mockController)
-	suite.branchValidation = branch.NewBranchFieldsValidation(suite.repo)
-	suite.addBranch = branch.NewAddBranchV2(suite.repo, suite.branchValidation)
+	suite.branchValidation = validator.NewBranchValidator()
+	suite.addBranch = branch.NewAddBranch(suite.repo, suite.branchValidation)
 
 	suite.checkOutRemoteBranch = NewCheckoutRemoteBranch(suite.mockRepo, suite.branchName, suite.mockAddBranch)
 }
@@ -67,7 +68,7 @@ func (suite *CheckOutRemoteBranchTestSuite) TearDownTest() {
 }
 
 func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenBranchIsValid_ShouldCheckoutLocalBranch() {
-	suite.checkOutRemoteBranch = NewCheckoutRemoteBranch(suite.repo, suite.branchName, suite.addBranch)
+	suite.checkOutRemoteBranch = NewCheckoutRemoteBranch(suite.repo, suite.branchName, nil)
 
 	err := suite.checkOutRemoteBranch.CheckoutBranch()
 
@@ -115,7 +116,7 @@ func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenCheckoutTreeF
 	suite.NotNil(err)
 }
 
-func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenLookupLocalBranch_ShouldAddNewLocalBranch() {
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenLookupLocalBranchFails_ShouldAddNewLocalBranch() {
 	gitCommit := &git2go.Commit{}
 
 	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
@@ -125,7 +126,7 @@ func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenLookupLocalBr
 	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
 	suite.mockRepo.EXPECT().LookupBranchV2(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
 	suite.mockCommit.EXPECT().GetGitCommit().Return(gitCommit)
-	suite.mockAddBranch.EXPECT().AddBranchV2(suite.branchName, false, gitCommit).Return(nil)
+	suite.mockAddBranch.EXPECT().AddBranch(suite.branchName, false, gitCommit).Return(nil)
 	suite.mockRepo.EXPECT().SetHead(suite.localBranchReferenceName).Return(nil)
 
 	err := suite.checkOutRemoteBranch.CheckoutBranch()
@@ -143,7 +144,7 @@ func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenLocalAddBranc
 	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
 	suite.mockRepo.EXPECT().LookupBranchV2(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
 	suite.mockCommit.EXPECT().GetGitCommit().Return(gitCommit)
-	suite.mockAddBranch.EXPECT().AddBranchV2(suite.branchName, false, gitCommit).Return(errors.New("ADD_ERROR"))
+	suite.mockAddBranch.EXPECT().AddBranch(suite.branchName, false, gitCommit).Return(errors.New("ADD_ERROR"))
 
 	err := suite.checkOutRemoteBranch.CheckoutBranch()
 
@@ -160,7 +161,7 @@ func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenSetHeadFailsA
 	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
 	suite.mockRepo.EXPECT().LookupBranchV2(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
 	suite.mockCommit.EXPECT().GetGitCommit().Return(gitCommit)
-	suite.mockAddBranch.EXPECT().AddBranchV2(suite.branchName, false, gitCommit).Return(nil)
+	suite.mockAddBranch.EXPECT().AddBranch(suite.branchName, false, gitCommit).Return(nil)
 	suite.mockRepo.EXPECT().SetHead(suite.localBranchReferenceName).Return(errors.New("SET_HEAD_ERROR"))
 
 	err := suite.checkOutRemoteBranch.CheckoutBranch()

From b2416606c01fe8b1fa0f634ee29eaad3ab8c942d Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 9 Sep 2021 00:51:27 +0530
Subject: [PATCH 117/148] fix file name type

---
 validator/{validaor.go => validator.go} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename validator/{validaor.go => validator.go} (100%)

diff --git a/validator/validaor.go b/validator/validator.go
similarity index 100%
rename from validator/validaor.go
rename to validator/validator.go

From d82774757455b12d0ef4555b164c436dd02d21aa Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Fri, 10 Sep 2021 18:50:50 +0530
Subject: [PATCH 118/148] update branch checkout factory to accept branch name
 as arg

---
 git/branch/checkout/checkout_factory.go      | 22 +++++++++-----------
 git/branch/checkout/checkout_factory_test.go | 16 +++++++-------
 2 files changed, 18 insertions(+), 20 deletions(-)

diff --git a/git/branch/checkout/checkout_factory.go b/git/branch/checkout/checkout_factory.go
index 483f1b4..1191718 100644
--- a/git/branch/checkout/checkout_factory.go
+++ b/git/branch/checkout/checkout_factory.go
@@ -9,48 +9,46 @@ import (
 )
 
 type Factory interface {
-	GetCheckoutAction() Checkout
+	GetCheckoutAction(branchName string) Checkout
 }
 
 type factory struct {
 	repo            middleware.Repository
-	branchName      string
 	repoValidator   validator.Validator
 	branchValidator validator.ValidatorWithStringFields
 }
 
-func (f factory) GetCheckoutAction() Checkout {
-	logger.Log(fmt.Sprintf("Received branch %s", f.branchName), global.StatusInfo)
+func (f factory) GetCheckoutAction(branchName string) Checkout {
+	logger.Log(fmt.Sprintf("Received branch %s", branchName), global.StatusInfo)
 	if repoValidationErr := f.repoValidator.Validate(); repoValidationErr != nil {
 		logger.Log(repoValidationErr.Error(), global.StatusError)
 		return nil
 	}
 
-	if validationErr := f.validateBranchFields(); validationErr != nil {
+	if validationErr := f.validateBranchFields(branchName); validationErr != nil {
 		return nil
 	}
 
-	if strings.Contains(f.branchName, "remotes/") {
-		return NewCheckoutRemoteBranch(f.repo, f.branchName, nil)
+	if strings.Contains(branchName, "remotes/") {
+		return NewCheckoutRemoteBranch(f.repo, branchName, nil)
 	} else {
-		return NewCheckOutLocalBranch(f.repo, f.branchName)
+		return NewCheckOutLocalBranch(f.repo, branchName)
 	}
 }
 
-func (f factory) validateBranchFields() error {
+func (f factory) validateBranchFields(branchName string) error {
 	logger.Log("Validating branch fields before checkout", global.StatusInfo)
 
-	if err := f.branchValidator.ValidateWithFields(f.branchName); err != nil {
+	if err := f.branchValidator.ValidateWithFields(branchName); err != nil {
 		logger.Log(err.Error(), global.StatusError)
 		return err
 	}
 	return nil
 }
 
-func NewCheckoutFactory(repo middleware.Repository, branchName string, repoValidator validator.Validator, branchValidator validator.ValidatorWithStringFields) Factory {
+func NewCheckoutFactory(repo middleware.Repository, repoValidator validator.Validator, branchValidator validator.ValidatorWithStringFields) Factory {
 	return factory{
 		repo:            repo,
-		branchName:      branchName,
 		repoValidator:   repoValidator,
 		branchValidator: branchValidator,
 	}
diff --git a/git/branch/checkout/checkout_factory_test.go b/git/branch/checkout/checkout_factory_test.go
index 1521336..9e7ec72 100644
--- a/git/branch/checkout/checkout_factory_test.go
+++ b/git/branch/checkout/checkout_factory_test.go
@@ -41,46 +41,46 @@ func (suite *CheckoutFactoryTestSuite) TearDownTest() {
 }
 
 func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsLocal_ShouldReturnLocalCheckoutAction() {
-	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.branchName, suite.mockRepoValidator, suite.mockBranchValidator)
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.mockRepoValidator, suite.mockBranchValidator)
 
 	suite.mockRepoValidator.EXPECT().Validate().Return(nil)
 	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
 
 	wantAction := NewCheckOutLocalBranch(suite.mockRepo, suite.branchName)
-	gotAction := suite.checkoutFactory.GetCheckoutAction()
+	gotAction := suite.checkoutFactory.GetCheckoutAction(suite.branchName)
 
 	suite.Equal(wantAction, gotAction)
 }
 
 func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsRemote_ShouldReturnRemoteCheckoutAction() {
-	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.remoteBranchName, suite.mockRepoValidator, suite.mockBranchValidator)
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.mockRepoValidator, suite.mockBranchValidator)
 
 	suite.mockRepoValidator.EXPECT().Validate().Return(nil)
 	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.remoteBranchName).Return(nil)
 
 	wantAction := NewCheckoutRemoteBranch(suite.mockRepo, suite.remoteBranchName, nil)
-	gotAction := suite.checkoutFactory.GetCheckoutAction()
+	gotAction := suite.checkoutFactory.GetCheckoutAction(suite.remoteBranchName)
 
 	suite.Equal(wantAction, gotAction)
 }
 
 func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenRepoValidationFails_ShouldReturnNil() {
-	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, "", suite.mockRepoValidator, suite.mockBranchValidator)
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.mockRepoValidator, suite.mockBranchValidator)
 
 	suite.mockRepoValidator.EXPECT().Validate().Return(validator.NilRepoError)
 
-	gotAction := suite.checkoutFactory.GetCheckoutAction()
+	gotAction := suite.checkoutFactory.GetCheckoutAction(suite.branchName)
 
 	suite.Nil(gotAction)
 }
 
 func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchValidationFails_ShouldReturnNil() {
-	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, "", suite.mockRepoValidator, suite.mockBranchValidator)
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.mockRepoValidator, suite.mockBranchValidator)
 
 	suite.mockRepoValidator.EXPECT().Validate().Return(nil)
 	suite.mockBranchValidator.EXPECT().ValidateWithFields("").Return(errors.New("VALIDATE_ERROR"))
 
-	gotAction := suite.checkoutFactory.GetCheckoutAction()
+	gotAction := suite.checkoutFactory.GetCheckoutAction("")
 
 	suite.Nil(gotAction)
 }

From 34558f01aaeff8b0f3e2c5597f0f1e869d346365 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 11 Sep 2021 12:48:15 +0530
Subject: [PATCH 119/148] update repo validator to accept repo object as
 function arg

---
 validator/repo_validator.go      | 13 ++++++++-----
 validator/repo_validator_test.go |  8 ++++----
 validator/validator.go           |  2 +-
 3 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/validator/repo_validator.go b/validator/repo_validator.go
index 9caa3e9..371648c 100644
--- a/validator/repo_validator.go
+++ b/validator/repo_validator.go
@@ -3,16 +3,19 @@ package validator
 import "github.com/neel1996/gitconvex/git/middleware"
 
 type repoValidator struct {
-	repo middleware.Repository
 }
 
-func (v repoValidator) Validate() error {
-	if v.repo == nil {
+func (v repoValidator) Validate(r interface{}) error {
+	if r == nil {
+		return NilRepoError
+	}
+
+	if repo, ok := r.(middleware.Repository); !ok || repo == nil {
 		return NilRepoError
 	}
 	return nil
 }
 
-func NewRepoValidator(repo middleware.Repository) Validator {
-	return repoValidator{repo: repo}
+func NewRepoValidator() Validator {
+	return repoValidator{}
 }
diff --git a/validator/repo_validator_test.go b/validator/repo_validator_test.go
index d65b1e8..5ee9df7 100644
--- a/validator/repo_validator_test.go
+++ b/validator/repo_validator_test.go
@@ -21,7 +21,7 @@ func TestRepoValidatorTestSuite(t *testing.T) {
 func (suite *RepoValidatorTestSuite) SetupTest() {
 	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.repoValidator = NewRepoValidator(suite.mockRepo)
+	suite.repoValidator = NewRepoValidator()
 }
 
 func (suite *RepoValidatorTestSuite) TearDownTest() {
@@ -29,15 +29,15 @@ func (suite *RepoValidatorTestSuite) TearDownTest() {
 }
 
 func (suite *RepoValidatorTestSuite) TestValidate_WhenRepoIsNotNil_ShouldReturnNil() {
-	err := suite.repoValidator.Validate()
+	err := suite.repoValidator.Validate(suite.mockRepo)
 
 	suite.Nil(err)
 }
 
 func (suite *RepoValidatorTestSuite) TestValidate_WhenRepoIsNil_ShouldReturnRepoNilError() {
-	suite.repoValidator = NewRepoValidator(nil)
+	suite.repoValidator = NewRepoValidator()
 
-	err := suite.repoValidator.Validate()
+	err := suite.repoValidator.Validate(nil)
 
 	suite.NotNil(err)
 	suite.Equal(NilRepoError, err)
diff --git a/validator/validator.go b/validator/validator.go
index 63893c4..1d38fdb 100644
--- a/validator/validator.go
+++ b/validator/validator.go
@@ -1,7 +1,7 @@
 package validator
 
 type Validator interface {
-	Validate() error
+	Validate(interface{}) error
 }
 
 type ValidatorWithStringFields interface {

From ecf18f50e368d7c6d31e9f8768ed1ef7552e2e2c Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 11 Sep 2021 18:16:08 +0530
Subject: [PATCH 120/148] refactor branch delete api with middleware functions
 and revised test suite

---
 git/branch/branch.go                          | 71 +--------------
 git/branch/git_branch_add_test.go             |  3 +-
 git/branch/git_branch_delete.go               | 22 ++---
 git/branch/git_branch_delete_test.go          | 88 +++++++++---------
 ...t_branch_add.go => mock_git_branch_add.go} | 22 +----
 git/middleware/branch.go                      |  5 ++
 mocks/mock_branch.go                          | 14 +++
 validator/mocks/mock_validator.go             | 89 +++++++++++++++++++
 8 files changed, 166 insertions(+), 148 deletions(-)
 rename git/branch/mocks/{git_branch_add.go => mock_git_branch_add.go} (56%)
 create mode 100644 validator/mocks/mock_validator.go

diff --git a/git/branch/branch.go b/git/branch/branch.go
index 226df48..2e458e5 100644
--- a/git/branch/branch.go
+++ b/git/branch/branch.go
@@ -1,74 +1,5 @@
 package branch
 
-import (
-	"errors"
-	"github.com/neel1996/gitconvex/git/branch/checkout"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-)
+import "github.com/neel1996/gitconvex/global"
 
 var logger global.Logger
-
-type Branch interface {
-	GitAddBranch() (string, error)
-	GitCheckoutBranch() (string, error)
-	GitCompareBranches() ([]*model.BranchCompareResults, error)
-	GitListBranches() (model.ListOfBranches, error)
-}
-
-type Operation struct {
-	Add      Add
-	Checkout checkout.Checkout
-	Compare  Compare
-	Delete   Delete
-	List     List
-}
-
-func (b Operation) GitAddBranch() (string, error) {
-	err := b.Add.AddBranch()
-
-	if err != nil {
-		return global.BranchAddError, err
-	}
-
-	return global.BranchAddSuccess, nil
-}
-
-func (b Operation) GitCheckoutBranch() (string, error) {
-	err := b.Checkout.CheckoutBranch()
-
-	if err != nil {
-		return global.BranchCheckoutError, err
-	}
-
-	return global.BranchCheckoutSuccess, nil
-}
-
-func (b Operation) GitCompareBranches() ([]*model.BranchCompareResults, error) {
-	branchDiff := b.Compare.CompareBranch()
-
-	if len(branchDiff) == 0 {
-		return []*model.BranchCompareResults{}, errors.New("no difference between the two branches")
-	}
-
-	return branchDiff, nil
-}
-
-func (b Operation) GitDeleteBranch() (*model.BranchDeleteStatus, error) {
-	err := b.Delete.DeleteBranch()
-
-	if err != nil {
-		return &model.BranchDeleteStatus{Status: global.BranchDeleteError}, err
-	}
-
-	return &model.BranchDeleteStatus{Status: global.BranchDeleteSuccess}, nil
-}
-
-func (b Operation) GitListBranches() (model.ListOfBranches, error) {
-	listOfBranches, err := b.List.ListBranches()
-	if err != nil {
-		return model.ListOfBranches{}, err
-	}
-
-	return listOfBranches, nil
-}
diff --git a/git/branch/git_branch_add_test.go b/git/branch/git_branch_add_test.go
index a2bd60e..98cfaf1 100644
--- a/git/branch/git_branch_add_test.go
+++ b/git/branch/git_branch_add_test.go
@@ -55,8 +55,7 @@ func (suite *BranchAddTestSuite) SetupTest() {
 }
 
 func (suite *BranchAddTestSuite) TearDownSuite() {
-	r, _ := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	_ = NewDeleteBranch(r, suite.branchName).DeleteBranch()
+	_ = NewDeleteBranch(suite.repo, validator.NewBranchValidator()).DeleteBranch(suite.branchName)
 	suite.mockController.Finish()
 }
 
diff --git a/git/branch/git_branch_delete.go b/git/branch/git_branch_delete.go
index 80c4d1e..94fab76 100644
--- a/git/branch/git_branch_delete.go
+++ b/git/branch/git_branch_delete.go
@@ -3,30 +3,30 @@ package branch
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/validator"
 )
 
 type Delete interface {
-	DeleteBranch() error
+	DeleteBranch(branchName string) error
 }
 
 type deleteBranch struct {
-	repo       *git2go.Repository
-	branchName string
+	repo            middleware.Repository
+	branchValidator validator.ValidatorWithStringFields
 }
 
-// DeleteBranch deletes a branch from the repo
-func (d deleteBranch) DeleteBranch() error {
+func (d deleteBranch) DeleteBranch(branchName string) error {
 	repo := d.repo
-	branchName := d.branchName
 
-	validationErr := NewBranchFieldsValidation(repo, branchName).ValidateBranchFields()
+	validationErr := d.branchValidator.ValidateWithFields(branchName)
 	if validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return validationErr
 	}
 
-	branch, deleteBranchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
+	branch, deleteBranchErr := repo.LookupBranchV2(branchName, git2go.BranchLocal)
 	if deleteBranchErr != nil {
 		logger.Log(fmt.Sprintf("Failed to delete branch %s -> %v", branchName, deleteBranchErr.Error()), global.StatusError)
 		return deleteBranchErr
@@ -42,9 +42,9 @@ func (d deleteBranch) DeleteBranch() error {
 	return nil
 }
 
-func NewDeleteBranch(repo *git2go.Repository, branchName string) Delete {
+func NewDeleteBranch(repo middleware.Repository, branchValidator validator.ValidatorWithStringFields) Delete {
 	return deleteBranch{
-		repo:       repo,
-		branchName: branchName,
+		repo:            repo,
+		branchValidator: branchValidator,
 	}
 }
diff --git a/git/branch/git_branch_delete_test.go b/git/branch/git_branch_delete_test.go
index 6bce2d8..0ed8c40 100644
--- a/git/branch/git_branch_delete_test.go
+++ b/git/branch/git_branch_delete_test.go
@@ -1,20 +1,29 @@
 package branch
 
 import (
+	"errors"
 	"fmt"
+	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/neel1996/gitconvex/validator"
+	mocks2 "github.com/neel1996/gitconvex/validator/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
-	"path/filepath"
 	"testing"
 )
 
 type BranchDeleteTestSuite struct {
 	suite.Suite
-	branchDelete Delete
-	branchName   string
-	repo         *git2go.Repository
-	noHeadRepo   *git2go.Repository
+	mockController      *gomock.Controller
+	branchDelete        Delete
+	branchName          string
+	repo                middleware.Repository
+	mockBranch          *mocks.MockBranch
+	branchValidator     validator.ValidatorWithStringFields
+	mockRepo            *mocks.MockRepository
+	mockBranchValidator *mocks2.MockValidatorWithStringFields
 }
 
 func TestBranchDeleteTestSuite(t *testing.T) {
@@ -22,18 +31,14 @@ func TestBranchDeleteTestSuite(t *testing.T) {
 }
 
 func (suite *BranchDeleteTestSuite) SetupTest() {
-	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	if err != nil {
-		fmt.Println(err)
-	}
+	suite.mockController = gomock.NewController(suite.T())
+	suite.branchName = "delete_branch"
 
-	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
-	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockBranchValidator = mocks2.NewMockValidatorWithStringFields(suite.mockController)
+	suite.mockBranch = mocks.NewMockBranch(suite.mockController)
 
-	suite.repo = r
-	suite.noHeadRepo = noHeadRepo
-	suite.branchName = "delete_branch"
-	suite.branchDelete = NewDeleteBranch(suite.repo, suite.branchName)
+	suite.branchDelete = NewDeleteBranch(suite.mockRepo, suite.mockBranchValidator)
 }
 
 func (suite *BranchDeleteTestSuite) SetupSuite() {
@@ -41,62 +46,51 @@ func (suite *BranchDeleteTestSuite) SetupSuite() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.repo = r
+
+	suite.repo = middleware.NewRepository(r)
+	suite.branchValidator = validator.NewBranchValidator()
 	suite.branchName = "delete_branch"
-	addErr := NewAddBranch(suite.repo, suite.branchName, false, nil).AddBranch()
+	addErr := NewAddBranch(suite.repo, validator.NewBranchValidator()).AddBranch(suite.branchName, false, nil)
 	if addErr != nil {
 		fmt.Println(addErr)
 	}
 }
 
-func (suite *BranchDeleteTestSuite) TearDownSuite() {
-	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	if err != nil {
-		fmt.Println(err)
-	}
-	_ = NewBranchCheckout(r, "master").CheckoutBranch()
+func (suite *BranchDeleteTestSuite) TearDownTest() {
+	suite.mockController.Finish()
 }
 
 func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchIsDeleted_ShouldReturnNil() {
-	err := suite.branchDelete.DeleteBranch()
+	suite.branchDelete = NewDeleteBranch(suite.repo, suite.branchValidator)
+
+	err := suite.branchDelete.DeleteBranch(suite.branchName)
 
 	suite.Nil(err)
 }
 
-func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenRepoIsNil_ShouldReturnError() {
-	suite.branchDelete = NewDeleteBranch(nil, suite.branchName)
-	err := suite.branchDelete.DeleteBranch()
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenValidationFails_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.branchName).Return(errors.New("VALIDATION_ERROR"))
 
-	suite.NotNil(err)
-}
-
-func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchNameIsEmpty_ShouldReturnError() {
-	suite.branchDelete = NewDeleteBranch(suite.repo, "")
-	err := suite.branchDelete.DeleteBranch()
+	err := suite.branchDelete.DeleteBranch(suite.branchName)
 
 	suite.NotNil(err)
 }
 
-func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenRepoHasNoHead_ShouldReturnError() {
-	suite.branchDelete = NewDeleteBranch(suite.noHeadRepo, suite.branchName)
-	err := suite.branchDelete.DeleteBranch()
-
-	suite.NotNil(err)
-}
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchLookupFails_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERR"))
 
-func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchDoesNotExists_ShouldReturnError() {
-	suite.branchDelete = NewDeleteBranch(suite.repo, "no_exists")
-	err := suite.branchDelete.DeleteBranch()
+	err := suite.branchDelete.DeleteBranch(suite.branchName)
 
 	suite.NotNil(err)
 }
 
-func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchIsCurrentBranch_ShouldReturnError() {
-	head, _ := suite.repo.Head()
-	name, _ := head.Branch().Name()
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchDeleteFails_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Delete().Return(errors.New("DELETE_ERROR"))
 
-	suite.branchDelete = NewDeleteBranch(suite.repo, name)
-	err := suite.branchDelete.DeleteBranch()
+	err := suite.branchDelete.DeleteBranch(suite.branchName)
 
 	suite.NotNil(err)
 }
diff --git a/git/branch/mocks/git_branch_add.go b/git/branch/mocks/mock_git_branch_add.go
similarity index 56%
rename from git/branch/mocks/git_branch_add.go
rename to git/branch/mocks/mock_git_branch_add.go
index ce1c990..174d835 100644
--- a/git/branch/mocks/git_branch_add.go
+++ b/git/branch/mocks/mock_git_branch_add.go
@@ -35,29 +35,15 @@ func (m *MockAdd) EXPECT() *MockAddMockRecorder {
 }
 
 // AddBranch mocks base method.
-func (m *MockAdd) AddBranch() error {
+func (m *MockAdd) AddBranch(branchName string, remoteSwitch bool, targetCommit *git.Commit) error {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "AddBranch")
+	ret := m.ctrl.Call(m, "AddBranch", branchName, remoteSwitch, targetCommit)
 	ret0, _ := ret[0].(error)
 	return ret0
 }
 
 // AddBranch indicates an expected call of AddBranch.
-func (mr *MockAddMockRecorder) AddBranch() *gomock.Call {
+func (mr *MockAddMockRecorder) AddBranch(branchName, remoteSwitch, targetCommit interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBranch", reflect.TypeOf((*MockAdd)(nil).AddBranch))
-}
-
-// AddBranchV2 mocks base method.
-func (m *MockAdd) AddBranchV2(branchName string, remoteSwitch bool, targetCommit *git.Commit) error {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "AddBranchV2", branchName, remoteSwitch, targetCommit)
-	ret0, _ := ret[0].(error)
-	return ret0
-}
-
-// AddBranchV2 indicates an expected call of AddBranchV2.
-func (mr *MockAddMockRecorder) AddBranchV2(branchName, remoteSwitch, targetCommit interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBranchV2", reflect.TypeOf((*MockAdd)(nil).AddBranchV2), branchName, remoteSwitch, targetCommit)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBranch", reflect.TypeOf((*MockAdd)(nil).AddBranch), branchName, remoteSwitch, targetCommit)
 }
diff --git a/git/middleware/branch.go b/git/middleware/branch.go
index b8f50ea..68b9feb 100644
--- a/git/middleware/branch.go
+++ b/git/middleware/branch.go
@@ -4,12 +4,17 @@ import git2go "github.com/libgit2/git2go/v31"
 
 type Branch interface {
 	Target() *git2go.Oid
+	Delete() error
 }
 
 type branch struct {
 	branch *git2go.Branch
 }
 
+func (b branch) Delete() error {
+	return b.branch.Delete()
+}
+
 func (b branch) Target() *git2go.Oid {
 	return b.branch.Target()
 }
diff --git a/mocks/mock_branch.go b/mocks/mock_branch.go
index 6038547..51e0d8a 100644
--- a/mocks/mock_branch.go
+++ b/mocks/mock_branch.go
@@ -34,6 +34,20 @@ func (m *MockBranch) EXPECT() *MockBranchMockRecorder {
 	return m.recorder
 }
 
+// Delete mocks base method.
+func (m *MockBranch) Delete() error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Delete")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Delete indicates an expected call of Delete.
+func (mr *MockBranchMockRecorder) Delete() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockBranch)(nil).Delete))
+}
+
 // Target mocks base method.
 func (m *MockBranch) Target() *git.Oid {
 	m.ctrl.T.Helper()
diff --git a/validator/mocks/mock_validator.go b/validator/mocks/mock_validator.go
new file mode 100644
index 0000000..d4337cf
--- /dev/null
+++ b/validator/mocks/mock_validator.go
@@ -0,0 +1,89 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: validator/validator.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockValidator is a mock of Validator interface.
+type MockValidator struct {
+	ctrl     *gomock.Controller
+	recorder *MockValidatorMockRecorder
+}
+
+// MockValidatorMockRecorder is the mock recorder for MockValidator.
+type MockValidatorMockRecorder struct {
+	mock *MockValidator
+}
+
+// NewMockValidator creates a new mock instance.
+func NewMockValidator(ctrl *gomock.Controller) *MockValidator {
+	mock := &MockValidator{ctrl: ctrl}
+	mock.recorder = &MockValidatorMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockValidator) EXPECT() *MockValidatorMockRecorder {
+	return m.recorder
+}
+
+// Validate mocks base method.
+func (m *MockValidator) Validate(arg0 interface{}) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Validate", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Validate indicates an expected call of Validate.
+func (mr *MockValidatorMockRecorder) Validate(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validate", reflect.TypeOf((*MockValidator)(nil).Validate), arg0)
+}
+
+// MockValidatorWithStringFields is a mock of ValidatorWithStringFields interface.
+type MockValidatorWithStringFields struct {
+	ctrl     *gomock.Controller
+	recorder *MockValidatorWithStringFieldsMockRecorder
+}
+
+// MockValidatorWithStringFieldsMockRecorder is the mock recorder for MockValidatorWithStringFields.
+type MockValidatorWithStringFieldsMockRecorder struct {
+	mock *MockValidatorWithStringFields
+}
+
+// NewMockValidatorWithStringFields creates a new mock instance.
+func NewMockValidatorWithStringFields(ctrl *gomock.Controller) *MockValidatorWithStringFields {
+	mock := &MockValidatorWithStringFields{ctrl: ctrl}
+	mock.recorder = &MockValidatorWithStringFieldsMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockValidatorWithStringFields) EXPECT() *MockValidatorWithStringFieldsMockRecorder {
+	return m.recorder
+}
+
+// ValidateWithFields mocks base method.
+func (m *MockValidatorWithStringFields) ValidateWithFields(fields ...string) error {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{}
+	for _, a := range fields {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ValidateWithFields", varargs...)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// ValidateWithFields indicates an expected call of ValidateWithFields.
+func (mr *MockValidatorWithStringFieldsMockRecorder) ValidateWithFields(fields ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateWithFields", reflect.TypeOf((*MockValidatorWithStringFields)(nil).ValidateWithFields), fields...)
+}

From 88dfdf760f0fcbde6af5495239f032616bb1e2cf Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 11 Sep 2021 18:16:56 +0530
Subject: [PATCH 121/148] add new mocks

---
 generate_all_mocks.sh | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/generate_all_mocks.sh b/generate_all_mocks.sh
index 4894f0b..6204f76 100755
--- a/generate_all_mocks.sh
+++ b/generate_all_mocks.sh
@@ -18,4 +18,7 @@ mockgen -source=git/remote/git_remote_list.go -destination=git/remote/mocks/mock
 mockgen -source=git/middleware/remotes.go -destination=git/remote/mocks/mock_remotes.go -package=mocks
 
 # Branch mocks
-mockgen -source=git/branch/git_branch_add.go  -destination=git/branch/mocks/git_branch_add.go -package=mocks
\ No newline at end of file
+mockgen -source=git/branch/git_branch_add.go  -destination=git/branch/mocks/mock_git_branch_add.go -package=mocks
+
+# Validator mocks
+mockgen -source=validator/validator.go -destination=validator/mocks/mock_validator.go -package=mocks

From 591ee574417890b6771d8c314d6f116586414e29 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 11 Sep 2021 18:20:33 +0530
Subject: [PATCH 122/148] update checkout factory with revised validator and
 revise TearDown stage in local branch checkout test

---
 git/branch/checkout/checkout_factory.go           |  2 +-
 git/branch/checkout/checkout_factory_test.go      | 11 +++++------
 git/branch/checkout/checkout_local_branch_test.go |  3 ++-
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/git/branch/checkout/checkout_factory.go b/git/branch/checkout/checkout_factory.go
index 1191718..5f34d04 100644
--- a/git/branch/checkout/checkout_factory.go
+++ b/git/branch/checkout/checkout_factory.go
@@ -20,7 +20,7 @@ type factory struct {
 
 func (f factory) GetCheckoutAction(branchName string) Checkout {
 	logger.Log(fmt.Sprintf("Received branch %s", branchName), global.StatusInfo)
-	if repoValidationErr := f.repoValidator.Validate(); repoValidationErr != nil {
+	if repoValidationErr := f.repoValidator.Validate(f.repo); repoValidationErr != nil {
 		logger.Log(repoValidationErr.Error(), global.StatusError)
 		return nil
 	}
diff --git a/git/branch/checkout/checkout_factory_test.go b/git/branch/checkout/checkout_factory_test.go
index 9e7ec72..63f47b7 100644
--- a/git/branch/checkout/checkout_factory_test.go
+++ b/git/branch/checkout/checkout_factory_test.go
@@ -43,7 +43,7 @@ func (suite *CheckoutFactoryTestSuite) TearDownTest() {
 func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsLocal_ShouldReturnLocalCheckoutAction() {
 	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.mockRepoValidator, suite.mockBranchValidator)
 
-	suite.mockRepoValidator.EXPECT().Validate().Return(nil)
+	suite.mockRepoValidator.EXPECT().Validate(suite.mockRepo).Return(nil)
 	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
 
 	wantAction := NewCheckOutLocalBranch(suite.mockRepo, suite.branchName)
@@ -55,7 +55,7 @@ func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsLocal_S
 func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsRemote_ShouldReturnRemoteCheckoutAction() {
 	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.mockRepoValidator, suite.mockBranchValidator)
 
-	suite.mockRepoValidator.EXPECT().Validate().Return(nil)
+	suite.mockRepoValidator.EXPECT().Validate(suite.mockRepo).Return(nil)
 	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.remoteBranchName).Return(nil)
 
 	wantAction := NewCheckoutRemoteBranch(suite.mockRepo, suite.remoteBranchName, nil)
@@ -65,10 +65,9 @@ func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsRemote_
 }
 
 func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenRepoValidationFails_ShouldReturnNil() {
-	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.mockRepoValidator, suite.mockBranchValidator)
-
-	suite.mockRepoValidator.EXPECT().Validate().Return(validator.NilRepoError)
+	suite.checkoutFactory = NewCheckoutFactory(nil, suite.mockRepoValidator, suite.mockBranchValidator)
 
+	suite.mockRepoValidator.EXPECT().Validate(nil).Return(validator.NilRepoError)
 	gotAction := suite.checkoutFactory.GetCheckoutAction(suite.branchName)
 
 	suite.Nil(gotAction)
@@ -77,7 +76,7 @@ func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenRepoValidationF
 func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchValidationFails_ShouldReturnNil() {
 	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.mockRepoValidator, suite.mockBranchValidator)
 
-	suite.mockRepoValidator.EXPECT().Validate().Return(nil)
+	suite.mockRepoValidator.EXPECT().Validate(suite.mockRepo).Return(nil)
 	suite.mockBranchValidator.EXPECT().ValidateWithFields("").Return(errors.New("VALIDATE_ERROR"))
 
 	gotAction := suite.checkoutFactory.GetCheckoutAction("")
diff --git a/git/branch/checkout/checkout_local_branch_test.go b/git/branch/checkout/checkout_local_branch_test.go
index fd3b9c9..e2f97d7 100644
--- a/git/branch/checkout/checkout_local_branch_test.go
+++ b/git/branch/checkout/checkout_local_branch_test.go
@@ -9,6 +9,7 @@ import (
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/neel1996/gitconvex/test_utils"
+	"github.com/neel1996/gitconvex/validator"
 	"github.com/stretchr/testify/suite"
 	"os"
 	"testing"
@@ -42,7 +43,7 @@ func (suite *CheckOutLocalBranchTestSuite) SetupSuite() {
 }
 
 func (suite *CheckOutLocalBranchTestSuite) TearDownSuite() {
-	branch.NewDeleteBranch(suite.repo.GetGitRepository(), suite.branchName)
+	branch.NewDeleteBranch(suite.repo, validator.NewBranchValidator())
 }
 
 func (suite *CheckOutLocalBranchTestSuite) SetupTest() {

From 51345706272c0836fe9229c6a48ee0027f2d053c Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 11 Sep 2021 19:00:29 +0530
Subject: [PATCH 123/148] add new init and controller layer for branch apis

---
 api/repo_status.go              |  3 +-
 controller/branch_controller.go | 86 +++++++++++++++++++++++++++++++++
 graph/resolver.go               | 28 +++++++++--
 graph/schema.resolvers.go       | 59 ++++++----------------
 init/init.go                    |  5 ++
 init/init_branch.go             | 44 +++++++++++++++++
 models/branch.go                | 14 ++++++
 7 files changed, 190 insertions(+), 49 deletions(-)
 create mode 100644 controller/branch_controller.go
 create mode 100644 init/init.go
 create mode 100644 init/init_branch.go
 create mode 100644 models/branch.go

diff --git a/api/repo_status.go b/api/repo_status.go
index 148e306..38db10b 100644
--- a/api/repo_status.go
+++ b/api/repo_status.go
@@ -97,8 +97,7 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	}
 
 	branchListObj := branch.NewBranchList(repo)
-	b := branch.Operation{List: branchListObj}
-	branchList, _ := b.GitListBranches()
+	branchList, _ := branchListObj.ListBranches()
 
 	currentBranch := branchList.CurrentBranch
 	branches := branchList.BranchList
diff --git a/controller/branch_controller.go b/controller/branch_controller.go
new file mode 100644
index 0000000..2d0cc3b
--- /dev/null
+++ b/controller/branch_controller.go
@@ -0,0 +1,86 @@
+package controller
+
+import (
+	"errors"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/branch/checkout"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+	"github.com/neel1996/gitconvex/models"
+)
+
+type BranchController interface {
+	GitAddBranch(branchName string, isRemoteBranch bool, targetCommit *git2go.Commit) (string, error)
+	GitCheckoutBranch(branchName string) (string, error)
+	GitDeleteBranch(branchName string) (*model.BranchDeleteStatus, error)
+	GitCompareBranches() ([]*model.BranchCompareResults, error)
+	GitListBranches() (model.ListOfBranches, error)
+}
+
+type branchController struct {
+	add             branch.Add
+	checkoutFactory checkout.Factory
+	compare         branch.Compare
+	delete          branch.Delete
+	list            branch.List
+}
+
+func (b branchController) GitAddBranch(branchName string, isRemoteBranch bool, targetCommit *git2go.Commit) (string, error) {
+	err := b.add.AddBranch(branchName, isRemoteBranch, targetCommit)
+
+	if err != nil {
+		return global.BranchAddError, err
+	}
+
+	return global.BranchAddSuccess, nil
+}
+
+func (b branchController) GitCheckoutBranch(branchName string) (string, error) {
+	err := b.checkoutFactory.GetCheckoutAction(branchName).CheckoutBranch()
+
+	if err != nil {
+		return global.BranchCheckoutError, err
+	}
+
+	return global.BranchCheckoutSuccess, nil
+}
+
+func (b branchController) GitCompareBranches() ([]*model.BranchCompareResults, error) {
+	branchDiff := b.compare.CompareBranch()
+
+	if len(branchDiff) == 0 {
+		return []*model.BranchCompareResults{}, errors.New("no difference between the two branches")
+	}
+
+	return branchDiff, nil
+}
+
+func (b branchController) GitDeleteBranch(branchName string) (*model.BranchDeleteStatus, error) {
+	err := b.delete.DeleteBranch(branchName)
+
+	if err != nil {
+		return &model.BranchDeleteStatus{Status: global.BranchDeleteError}, err
+	}
+
+	return &model.BranchDeleteStatus{Status: global.BranchDeleteSuccess}, nil
+}
+
+func (b branchController) GitListBranches() (model.ListOfBranches, error) {
+	listOfBranches, err := b.list.ListBranches()
+	if err != nil {
+		return model.ListOfBranches{}, err
+	}
+
+	return listOfBranches, nil
+}
+
+func NewBranchController(branchModel models.Branch) BranchController {
+	return branchController{
+		add:             branchModel.Add,
+		checkoutFactory: branchModel.Checkout,
+		compare:         branchModel.Compare,
+		delete:          branchModel.Delete,
+		list:            branchModel.List,
+	}
+}
diff --git a/graph/resolver.go b/graph/resolver.go
index a25c09c..35effa5 100644
--- a/graph/resolver.go
+++ b/graph/resolver.go
@@ -1,7 +1,29 @@
 package graph
 
-// This file will not be regenerated automatically.
-//
-// It serves as dependency injection for your app, add any dependencies you require here.
+import (
+	"context"
+	"github.com/neel1996/gitconvex/controller"
+	"github.com/neel1996/gitconvex/git/middleware"
+	initialize "github.com/neel1996/gitconvex/init"
+	"github.com/neel1996/gitconvex/models"
+	"github.com/neel1996/gitconvex/validator"
+)
 
 type Resolver struct{}
+
+func (r *Resolver) BranchController(ctx context.Context, repo middleware.Repository) controller.BranchController {
+	repoValidator := validator.NewRepoValidator()
+	if repoValidator.Validate(repo) != nil {
+		ctx.Done()
+		return nil
+	}
+	branchObject := initialize.NewInitBranch(repo)
+
+	branchModel := models.Branch{
+		Add:      branchObject.BranchAdd(),
+		Checkout: branchObject.BranchCheckout(),
+		Delete:   branchObject.BranchDelete(),
+	}
+
+	return controller.NewBranchController(branchModel)
+}
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index b987be2..0e9fa91 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -45,16 +45,13 @@ func (r *mutationResolver) AddBranch(ctx context.Context, repoID string, branchN
 	repoObject = git.RepoStruct{RepoId: repoID}
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
-	if repo.GitRepo == nil {
-		logger.Log("Repo is invalid. Branch addition failed", global.StatusError)
+
+	branchController := r.BranchController(ctx, middleware.NewRepository(repo.GitRepo))
+	if branchController == nil {
 		return global.BranchAddError, nil
 	}
 
-	addBranch := branch.NewAddBranch(repo.GitRepo, branchName, false, nil)
-	b := branch.Operation{
-		Add: addBranch,
-	}
-	return b.GitAddBranch()
+	return branchController.GitAddBranch(branchName, false, nil)
 }
 
 func (r *mutationResolver) CheckoutBranch(ctx context.Context, repoID string, branchName string) (string, error) {
@@ -67,16 +64,13 @@ func (r *mutationResolver) CheckoutBranch(ctx context.Context, repoID string, br
 	go repoObject.Repo(repoChan)
 
 	repo := <-repoChan
-	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil {
-		logger.Log("Repository is invalid or HEAD is null", global.StatusError)
+
+	branchController := r.BranchController(ctx, middleware.NewRepository(repo.GitRepo))
+	if branchController == nil {
 		return global.BranchCheckoutError, nil
 	}
 
-	checkOutBranch := branch.NewBranchCheckout(repo.GitRepo, branchName)
-	b := branch.Operation{
-		Checkout: checkOutBranch,
-	}
-	return b.GitCheckoutBranch()
+	return branchController.GitCheckoutBranch(branchName)
 }
 
 func (r *mutationResolver) DeleteBranch(ctx context.Context, repoID string, branchName string, forceFlag bool) (*model.BranchDeleteStatus, error) {
@@ -87,18 +81,15 @@ func (r *mutationResolver) DeleteBranch(ctx context.Context, repoID string, bran
 	repoObject = git.RepoStruct{RepoId: repoID}
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
-	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil {
-		logger.Log("Repo is invalid or HEAD is null", global.StatusError)
+
+	branchController := r.BranchController(ctx, middleware.NewRepository(repo.GitRepo))
+	if branchController == nil {
 		return &model.BranchDeleteStatus{
 			Status: global.BranchDeleteError,
 		}, nil
 	}
 
-	deleteBranch := branch.NewDeleteBranch(repo.GitRepo, branchName)
-	b := branch.Operation{
-		Delete: deleteBranch,
-	}
-	return b.GitDeleteBranch()
+	return branchController.GitDeleteBranch(branchName)
 }
 
 func (r *mutationResolver) FetchFromRemote(ctx context.Context, repoID string, remoteURL *string, remoteBranch *string) (*model.FetchResult, error) {
@@ -119,9 +110,6 @@ func (r *mutationResolver) FetchFromRemote(ctx context.Context, repoID string, r
 		}, nil
 	}
 
-	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
-	context.WithValue(ctx, initialize.RemoteUrl, remoteURL)
-
 	remoteName := initialize.RemoteObjects(ctx).RemoteName
 
 	var fetchObject git.FetchInterface
@@ -274,7 +262,6 @@ func (r *mutationResolver) PushToRemote(ctx context.Context, repoID string, remo
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
 
-	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
 	remoteName := initialize.RemoteObjects(ctx).RemoteName.GetRemoteNameWithUrl()
 
 	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil || remoteName == "" {
@@ -330,10 +317,6 @@ func (r *mutationResolver) AddRemote(ctx context.Context, repoID string, remoteN
 		return &model.RemoteMutationResult{Status: global.RemoteAddError}, nil
 	}
 
-	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
-	context.WithValue(ctx, initialize.RemoteName, remoteName)
-	context.WithValue(ctx, initialize.RemoteUrl, remoteURL)
-
 	addRemote := initialize.RemoteObjects(ctx).AddRemote
 	remoteObject := remote.Operation{Add: addRemote}
 
@@ -353,9 +336,6 @@ func (r *mutationResolver) DeleteRemote(ctx context.Context, repoID string, remo
 		return &model.RemoteMutationResult{Status: global.RemoteAddError}, nil
 	}
 
-	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
-	context.WithValue(ctx, initialize.RemoteName, remoteName)
-
 	deleteRemote := initialize.RemoteObjects(ctx).DeleteRemote
 
 	remoteObject := remote.Operation{
@@ -379,9 +359,6 @@ func (r *mutationResolver) EditRemote(ctx context.Context, repoID string, remote
 		return &model.RemoteMutationResult{Status: constants.RemoteEditError.Error()}, nil
 	}
 
-	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
-	context.WithValue(ctx, initialize.RemoteName, remoteName)
-
 	editRemote := initialize.RemoteObjects(ctx).EditRemote
 	editRemoteObject := remote.Operation{
 		Edit: editRemote,
@@ -515,7 +492,6 @@ func (r *queryResolver) GitUnPushedCommits(ctx context.Context, repoID string, r
 		return nil, nil
 	}
 
-	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
 	remoteName := initialize.RemoteObjects(ctx).RemoteName.GetRemoteNameWithUrl()
 
 	remoteRef := remoteName + "/" + remoteBranch
@@ -613,11 +589,8 @@ func (r *queryResolver) BranchCompare(ctx context.Context, repoID string, baseBr
 		}, nil
 	}
 
-	branchCompare := branch.NewBranchCompare(repo.GitRepo, baseBranch, compareBranch)
-	b := branch.Operation{
-		Compare: branchCompare,
-	}
-	return b.GitCompareBranches()
+	branchCompare := branch.NewBranchCompare(middleware.NewRepository(repo.GitRepo), baseBranch, compareBranch, nil)
+	return branchCompare.CompareBranch(), nil
 }
 
 func (r *queryResolver) GetRemote(ctx context.Context, repoID string) ([]*model.RemoteDetails, error) {
@@ -627,9 +600,7 @@ func (r *queryResolver) GetRemote(ctx context.Context, repoID string) ([]*model.
 	var repoObject git.RepoInterface
 	repoObject = git.RepoStruct{RepoId: repoID}
 	go repoObject.Repo(repoChan)
-	repo := <-repoChan
-
-	context.WithValue(ctx, initialize.Repo, repo.GitRepo)
+	//repo := <-repoChan
 
 	listRemote := initialize.RemoteObjects(ctx).ListRemote
 	remoteUrlList := remote.Operation{List: listRemote}
diff --git a/init/init.go b/init/init.go
new file mode 100644
index 0000000..187ab4e
--- /dev/null
+++ b/init/init.go
@@ -0,0 +1,5 @@
+package initialize
+
+import "github.com/neel1996/gitconvex/global"
+
+var logger global.Logger
diff --git a/init/init_branch.go b/init/init_branch.go
new file mode 100644
index 0000000..a2b567c
--- /dev/null
+++ b/init/init_branch.go
@@ -0,0 +1,44 @@
+package initialize
+
+import (
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/branch/checkout"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/validator"
+)
+
+var (
+	repoValidator   validator.Validator
+	branchValidator validator.ValidatorWithStringFields
+)
+
+type InitBranch interface {
+	BranchAdd() branch.Add
+	BranchDelete() branch.Delete
+	BranchCheckout() checkout.Factory
+}
+
+type initBranch struct {
+	repo middleware.Repository
+}
+
+func init() {
+	repoValidator = validator.NewRepoValidator()
+	branchValidator = validator.NewBranchValidator()
+}
+
+func (i initBranch) BranchAdd() branch.Add {
+	return branch.NewAddBranch(i.repo, branchValidator)
+}
+
+func (i initBranch) BranchDelete() branch.Delete {
+	return branch.NewDeleteBranch(i.repo, branchValidator)
+}
+
+func (i initBranch) BranchCheckout() checkout.Factory {
+	return checkout.NewCheckoutFactory(i.repo, repoValidator, branchValidator)
+}
+
+func NewInitBranch(repo middleware.Repository) InitBranch {
+	return initBranch{repo: repo}
+}
diff --git a/models/branch.go b/models/branch.go
new file mode 100644
index 0000000..ba9fffe
--- /dev/null
+++ b/models/branch.go
@@ -0,0 +1,14 @@
+package models
+
+import (
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/branch/checkout"
+)
+
+type Branch struct {
+	Add      branch.Add
+	Checkout checkout.Factory
+	Compare  branch.Compare
+	Delete   branch.Delete
+	List     branch.List
+}

From 2b7111c7f3aba8b43e0d8130ef5f5d6a6faf3859 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 12 Sep 2021 11:12:02 +0530
Subject: [PATCH 124/148] add new test utils to use in branch api unit test
 suites

---
 git/branch/test_utils/add_branch_util.go      | 12 ++++++++
 git/branch/test_utils/checkout_branch_util.go | 18 ++++++++++++
 git/branch/test_utils/delete_branch_util.go   | 12 ++++++++
 .../test_utils/stage_and_commit_util.go       | 28 +++++++++++++++++++
 4 files changed, 70 insertions(+)
 create mode 100644 git/branch/test_utils/add_branch_util.go
 create mode 100644 git/branch/test_utils/checkout_branch_util.go
 create mode 100644 git/branch/test_utils/delete_branch_util.go
 create mode 100644 git/branch/test_utils/stage_and_commit_util.go

diff --git a/git/branch/test_utils/add_branch_util.go b/git/branch/test_utils/add_branch_util.go
new file mode 100644
index 0000000..755b249
--- /dev/null
+++ b/git/branch/test_utils/add_branch_util.go
@@ -0,0 +1,12 @@
+package test_utils
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+func AddTestBranch(repo middleware.Repository, branchName string) {
+	head, _ := repo.Head()
+	targetCommit, _ := repo.LookupCommit(head.Target())
+	fmt.Println(repo.CreateBranch(branchName, targetCommit, false))
+}
diff --git a/git/branch/test_utils/checkout_branch_util.go b/git/branch/test_utils/checkout_branch_util.go
new file mode 100644
index 0000000..53c9d1f
--- /dev/null
+++ b/git/branch/test_utils/checkout_branch_util.go
@@ -0,0 +1,18 @@
+package test_utils
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+func CheckoutTestBranch(repo middleware.Repository, branchName string) {
+	branch, _ := repo.LookupBranch(branchName, git2go.BranchLocal)
+	targetCommit, _ := repo.LookupCommitV2(branch.Target())
+	tree, _ := targetCommit.Tree()
+	_ = repo.CheckoutTree(tree, &git2go.CheckoutOptions{
+		Strategy:       git2go.CheckoutSafe,
+		DisableFilters: false,
+	})
+	fmt.Println(repo.SetHead("refs/heads/" + branchName))
+}
diff --git a/git/branch/test_utils/delete_branch_util.go b/git/branch/test_utils/delete_branch_util.go
new file mode 100644
index 0000000..0e5ee01
--- /dev/null
+++ b/git/branch/test_utils/delete_branch_util.go
@@ -0,0 +1,12 @@
+package test_utils
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+func DeleteTestBranch(repo middleware.Repository, branchName string) {
+	branch, _ := repo.LookupBranch(branchName, git2go.BranchLocal)
+	fmt.Println(branch.Delete())
+}
diff --git a/git/branch/test_utils/stage_and_commit_util.go b/git/branch/test_utils/stage_and_commit_util.go
new file mode 100644
index 0000000..1dfbb1c
--- /dev/null
+++ b/git/branch/test_utils/stage_and_commit_util.go
@@ -0,0 +1,28 @@
+package test_utils
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"io/ioutil"
+)
+
+func StageAndCommitTestFile(repo middleware.Repository, branchName string, testFile string) {
+	AddTestBranch(repo, branchName)
+	CheckoutTestBranch(repo, branchName)
+
+	for i := 1; i <= 2; i++ {
+		err := ioutil.WriteFile(testFile, []byte{byte(i)}, 0644)
+		if err != nil {
+			fmt.Println(err.Error())
+			return
+		}
+
+		git.StageItemStruct{
+			Repo:     repo.GetGitRepository(),
+			FileItem: testFile,
+		}.StageItem()
+		fmt.Println(commit.NewCommitChanges(repo, []string{fmt.Sprintf("Branch compare test commit - %v", i)}).Add())
+	}
+}

From 7643ea2bfdc7d05c9a9e7e7a1aef29da598dfcec Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 12 Sep 2021 11:59:48 +0530
Subject: [PATCH 125/148] update branch lookup function

---
 git/branch/checkout/checkout_local_branch.go  |  2 +-
 .../checkout/checkout_local_branch_test.go    | 10 ++++----
 git/branch/checkout/checkout_remote_branch.go |  4 ++--
 .../checkout/checkout_remote_branch_test.go   | 24 +++++++++----------
 git/branch/git_branch_delete.go               |  2 +-
 git/branch/git_branch_delete_test.go          |  4 ++--
 git/middleware/repository.go                  |  9 ++-----
 mocks/mock_repository.go                      | 19 ++-------------
 8 files changed, 27 insertions(+), 47 deletions(-)

diff --git a/git/branch/checkout/checkout_local_branch.go b/git/branch/checkout/checkout_local_branch.go
index 87db5a4..fc983e9 100644
--- a/git/branch/checkout/checkout_local_branch.go
+++ b/git/branch/checkout/checkout_local_branch.go
@@ -18,7 +18,7 @@ func (c checkOutLocalBranch) CheckoutBranch() error {
 
 	logger.Log(fmt.Sprintf("Initiating local branch checkout for %s", branchName), global.StatusInfo)
 
-	branch, branchErr := repo.LookupBranchV2(branchName, git2go.BranchLocal)
+	branch, branchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
 	if branchErr != nil {
 		return c.LogAndReturnError(branchErr)
 	}
diff --git a/git/branch/checkout/checkout_local_branch_test.go b/git/branch/checkout/checkout_local_branch_test.go
index e2f97d7..70b8e77 100644
--- a/git/branch/checkout/checkout_local_branch_test.go
+++ b/git/branch/checkout/checkout_local_branch_test.go
@@ -68,7 +68,7 @@ func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenBranchIsValid_
 }
 
 func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenBranchLookupFails_ShouldReturnError() {
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
 
 	err := suite.checkOutLocalBranch.CheckoutBranch()
 
@@ -76,7 +76,7 @@ func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenBranchLookupFa
 }
 
 func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenCommitLookupFails_ShouldReturnError() {
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
 	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
 	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(nil, errors.New("LOOKUP_ERROR"))
 
@@ -86,7 +86,7 @@ func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenCommitLookupFa
 }
 
 func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenFetchCommitTreeFails_ShouldReturnError() {
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
 	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
 	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
 	suite.mockCommit.EXPECT().Tree().Return(nil, errors.New("TREE_ERROR"))
@@ -97,7 +97,7 @@ func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenFetchCommitTre
 }
 
 func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenCheckoutTreeFails_ShouldReturnError() {
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
 	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
 	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
 	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
@@ -111,7 +111,7 @@ func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenCheckoutTreeFa
 func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenSetHeadFails_ShouldReturnError() {
 	referenceName := "refs/heads/" + suite.branchName
 
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
 	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
 	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
 	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
diff --git a/git/branch/checkout/checkout_remote_branch.go b/git/branch/checkout/checkout_remote_branch.go
index 3b64fc0..2f0ace3 100644
--- a/git/branch/checkout/checkout_remote_branch.go
+++ b/git/branch/checkout/checkout_remote_branch.go
@@ -24,7 +24,7 @@ func (c checkOutRemoteBranch) CheckoutBranch() error {
 	branchFields := c.GenerateBranchFields()
 
 	logger.Log(fmt.Sprintf("Branch - %s is a remote branch. Trying with intermediate remote fetch!", branchName), global.StatusWarning)
-	remoteBranch, remoteBranchErr := repo.LookupBranchV2(branchFields.RemoteBranchName, git2go.BranchRemote)
+	remoteBranch, remoteBranchErr := repo.LookupBranch(branchFields.RemoteBranchName, git2go.BranchRemote)
 	if remoteBranchErr != nil {
 		return c.LogAndReturnError(remoteBranchErr)
 	}
@@ -45,7 +45,7 @@ func (c checkOutRemoteBranch) CheckoutBranch() error {
 		return c.LogAndReturnError(checkoutErr)
 	}
 
-	_, localLookupErr := repo.LookupBranchV2(branchFields.BranchName, git2go.BranchLocal)
+	_, localLookupErr := repo.LookupBranch(branchFields.BranchName, git2go.BranchLocal)
 	if localLookupErr != nil {
 		logger.Log(localLookupErr.Error(), global.StatusError)
 		gitCommit := remoteCommit.GetGitCommit()
diff --git a/git/branch/checkout/checkout_remote_branch_test.go b/git/branch/checkout/checkout_remote_branch_test.go
index 3afa5c1..8c29ec6 100644
--- a/git/branch/checkout/checkout_remote_branch_test.go
+++ b/git/branch/checkout/checkout_remote_branch_test.go
@@ -76,7 +76,7 @@ func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenBranchIsValid
 }
 
 func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenBranchLookupFails_ShouldReturnError() {
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(nil, errors.New("LOOKUP_ERROR"))
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(nil, errors.New("LOOKUP_ERROR"))
 
 	err := suite.checkOutRemoteBranch.CheckoutBranch()
 
@@ -84,7 +84,7 @@ func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenBranchLookupF
 }
 
 func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenCommitLookupFails_ShouldReturnError() {
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
 	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
 	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(nil, errors.New("LOOKUP_ERROR"))
 
@@ -94,7 +94,7 @@ func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenCommitLookupF
 }
 
 func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenFetchCommitTreeFails_ShouldReturnError() {
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
 	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
 	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
 	suite.mockCommit.EXPECT().Tree().Return(nil, errors.New("TREE_ERROR"))
@@ -105,7 +105,7 @@ func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenFetchCommitTr
 }
 
 func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenCheckoutTreeFails_ShouldReturnError() {
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
 	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
 	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
 	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
@@ -119,12 +119,12 @@ func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenCheckoutTreeF
 func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenLookupLocalBranchFails_ShouldAddNewLocalBranch() {
 	gitCommit := &git2go.Commit{}
 
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
 	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
 	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
 	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
 	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+	suite.mockRepo.EXPECT().LookupBranch(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
 	suite.mockCommit.EXPECT().GetGitCommit().Return(gitCommit)
 	suite.mockAddBranch.EXPECT().AddBranch(suite.branchName, false, gitCommit).Return(nil)
 	suite.mockRepo.EXPECT().SetHead(suite.localBranchReferenceName).Return(nil)
@@ -137,12 +137,12 @@ func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenLookupLocalBr
 func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenLocalAddBranchFails_ShouldReturnError() {
 	gitCommit := &git2go.Commit{}
 
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
 	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
 	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
 	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
 	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+	suite.mockRepo.EXPECT().LookupBranch(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
 	suite.mockCommit.EXPECT().GetGitCommit().Return(gitCommit)
 	suite.mockAddBranch.EXPECT().AddBranch(suite.branchName, false, gitCommit).Return(errors.New("ADD_ERROR"))
 
@@ -154,12 +154,12 @@ func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenLocalAddBranc
 func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenSetHeadFailsAfterAddingNewBranch_ShouldReturnError() {
 	gitCommit := &git2go.Commit{}
 
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
 	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
 	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
 	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
 	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+	suite.mockRepo.EXPECT().LookupBranch(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
 	suite.mockCommit.EXPECT().GetGitCommit().Return(gitCommit)
 	suite.mockAddBranch.EXPECT().AddBranch(suite.branchName, false, gitCommit).Return(nil)
 	suite.mockRepo.EXPECT().SetHead(suite.localBranchReferenceName).Return(errors.New("SET_HEAD_ERROR"))
@@ -170,12 +170,12 @@ func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenSetHeadFailsA
 }
 
 func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenSetHeadFails_ShouldReturnError() {
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
 	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
 	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
 	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
 	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.localBranchName, git2go.BranchLocal).Return(nil, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.localBranchName, git2go.BranchLocal).Return(nil, nil)
 	suite.mockRepo.EXPECT().SetHead(suite.localBranchReferenceName).Return(errors.New("SET_HEAD_ERROR"))
 
 	err := suite.checkOutRemoteBranch.CheckoutBranch()
diff --git a/git/branch/git_branch_delete.go b/git/branch/git_branch_delete.go
index 94fab76..be4c8cc 100644
--- a/git/branch/git_branch_delete.go
+++ b/git/branch/git_branch_delete.go
@@ -26,7 +26,7 @@ func (d deleteBranch) DeleteBranch(branchName string) error {
 		return validationErr
 	}
 
-	branch, deleteBranchErr := repo.LookupBranchV2(branchName, git2go.BranchLocal)
+	branch, deleteBranchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
 	if deleteBranchErr != nil {
 		logger.Log(fmt.Sprintf("Failed to delete branch %s -> %v", branchName, deleteBranchErr.Error()), global.StatusError)
 		return deleteBranchErr
diff --git a/git/branch/git_branch_delete_test.go b/git/branch/git_branch_delete_test.go
index 0ed8c40..f79abf3 100644
--- a/git/branch/git_branch_delete_test.go
+++ b/git/branch/git_branch_delete_test.go
@@ -78,7 +78,7 @@ func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenValidationFails_ShouldR
 
 func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchLookupFails_ShouldReturnError() {
 	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERR"))
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERR"))
 
 	err := suite.branchDelete.DeleteBranch(suite.branchName)
 
@@ -87,7 +87,7 @@ func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchLookupFails_Shoul
 
 func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchDeleteFails_ShouldReturnError() {
 	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
-	suite.mockRepo.EXPECT().LookupBranchV2(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
 	suite.mockBranch.EXPECT().Delete().Return(errors.New("DELETE_ERROR"))
 
 	err := suite.branchDelete.DeleteBranch(suite.branchName)
diff --git a/git/middleware/repository.go b/git/middleware/repository.go
index bb6ca0b..dfb8d8d 100644
--- a/git/middleware/repository.go
+++ b/git/middleware/repository.go
@@ -14,8 +14,7 @@ type Repository interface {
 	CreateCommit(s string, signature *git.Signature, signature2 *git.Signature, message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error)
 	DiffTreeToTree(tree *git.Tree, tree2 *git.Tree, options *git.DiffOptions) (*git.Diff, error)
 	CreateBranch(string, *git.Commit, bool) (*git.Branch, error)
-	LookupBranch(branchName string, branchType git.BranchType) (*git.Branch, error)
-	LookupBranchV2(branchName string, branchType git.BranchType) (Branch, error)
+	LookupBranch(branchName string, branchType git.BranchType) (Branch, error)
 	CheckoutTree(tree *git.Tree, c *git.CheckoutOptions) error
 	SetHead(name string) error
 	GetGitRepository() *git.Repository
@@ -74,11 +73,7 @@ func (r repository) LookupCommitV2(oid *git.Oid) (Commit, error) {
 	return NewCommit(gitCommit), nil
 }
 
-func (r repository) LookupBranch(branchName string, branchType git.BranchType) (*git.Branch, error) {
-	return r.repo.LookupBranch(branchName, branchType)
-}
-
-func (r repository) LookupBranchV2(branchName string, branchType git.BranchType) (Branch, error) {
+func (r repository) LookupBranch(branchName string, branchType git.BranchType) (Branch, error) {
 	gitBranch, err := r.repo.LookupBranch(branchName, branchType)
 	if err != nil {
 		return nil, err
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
index 7446e2c..bb6499b 100644
--- a/mocks/mock_repository.go
+++ b/mocks/mock_repository.go
@@ -159,10 +159,10 @@ func (mr *MockRepositoryMockRecorder) Index() *gomock.Call {
 }
 
 // LookupBranch mocks base method.
-func (m *MockRepository) LookupBranch(branchName string, branchType git.BranchType) (*git.Branch, error) {
+func (m *MockRepository) LookupBranch(branchName string, branchType git.BranchType) (middleware.Branch, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "LookupBranch", branchName, branchType)
-	ret0, _ := ret[0].(*git.Branch)
+	ret0, _ := ret[0].(middleware.Branch)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
@@ -173,21 +173,6 @@ func (mr *MockRepositoryMockRecorder) LookupBranch(branchName, branchType interf
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupBranch", reflect.TypeOf((*MockRepository)(nil).LookupBranch), branchName, branchType)
 }
 
-// LookupBranchV2 mocks base method.
-func (m *MockRepository) LookupBranchV2(branchName string, branchType git.BranchType) (middleware.Branch, error) {
-	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "LookupBranchV2", branchName, branchType)
-	ret0, _ := ret[0].(middleware.Branch)
-	ret1, _ := ret[1].(error)
-	return ret0, ret1
-}
-
-// LookupBranchV2 indicates an expected call of LookupBranchV2.
-func (mr *MockRepositoryMockRecorder) LookupBranchV2(branchName, branchType interface{}) *gomock.Call {
-	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupBranchV2", reflect.TypeOf((*MockRepository)(nil).LookupBranchV2), branchName, branchType)
-}
-
 // LookupCommit mocks base method.
 func (m *MockRepository) LookupCommit(oid *git.Oid) (*git.Commit, error) {
 	m.ctrl.T.Helper()

From 7bad400444c55ce8d803e663e31b8d9683d8597f Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 12 Sep 2021 12:00:07 +0530
Subject: [PATCH 126/148] remove unused test util

---
 test_utils/checkout_test_local_branch.go | 15 ---------------
 1 file changed, 15 deletions(-)
 delete mode 100644 test_utils/checkout_test_local_branch.go

diff --git a/test_utils/checkout_test_local_branch.go b/test_utils/checkout_test_local_branch.go
deleted file mode 100644
index cb948af..0000000
--- a/test_utils/checkout_test_local_branch.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package test_utils
-
-import (
-	"github.com/neel1996/gitconvex/git/branch/checkout"
-	"github.com/neel1996/gitconvex/git/middleware"
-	"log"
-)
-
-func CheckoutTestLocalBranch(repo middleware.Repository, branchName string) {
-	err := checkout.NewCheckOutLocalBranch(repo, branchName).CheckoutBranch()
-	if err != nil {
-		log.Println(err)
-		return
-	}
-}

From 2529f7a967b1bd33200e0da3da0eb16a8822623d Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 12 Sep 2021 12:00:47 +0530
Subject: [PATCH 127/148] update branch compare api and test suite

---
 controller/branch_controller.go       |  13 +-
 git/branch/errors.go                  |   3 +
 git/branch/git_branch_compare.go      | 138 +++++++++++++--------
 git/branch/git_branch_compare_test.go | 168 ++++++++++++++++++--------
 git/middleware/branch.go              |  10 ++
 git/middleware/commit.go              |  17 ++-
 git/middleware/reference.go           |   5 +
 graph/schema.resolvers.go             |  10 +-
 mocks/mock_branch.go                  |  29 +++++
 mocks/mock_commit.go                  |  28 +++++
 mocks/mock_reference.go               |  14 +++
 11 files changed, 317 insertions(+), 118 deletions(-)

diff --git a/controller/branch_controller.go b/controller/branch_controller.go
index 2d0cc3b..9b658c2 100644
--- a/controller/branch_controller.go
+++ b/controller/branch_controller.go
@@ -1,7 +1,6 @@
 package controller
 
 import (
-	"errors"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/neel1996/gitconvex/git/branch/checkout"
@@ -14,7 +13,7 @@ type BranchController interface {
 	GitAddBranch(branchName string, isRemoteBranch bool, targetCommit *git2go.Commit) (string, error)
 	GitCheckoutBranch(branchName string) (string, error)
 	GitDeleteBranch(branchName string) (*model.BranchDeleteStatus, error)
-	GitCompareBranches() ([]*model.BranchCompareResults, error)
+	GitCompareBranches(baseBranch string, compareBranch string) ([]*model.BranchCompareResults, error)
 	GitListBranches() (model.ListOfBranches, error)
 }
 
@@ -46,14 +45,8 @@ func (b branchController) GitCheckoutBranch(branchName string) (string, error) {
 	return global.BranchCheckoutSuccess, nil
 }
 
-func (b branchController) GitCompareBranches() ([]*model.BranchCompareResults, error) {
-	branchDiff := b.compare.CompareBranch()
-
-	if len(branchDiff) == 0 {
-		return []*model.BranchCompareResults{}, errors.New("no difference between the two branches")
-	}
-
-	return branchDiff, nil
+func (b branchController) GitCompareBranches(baseBranch string, compareBranch string) ([]*model.BranchCompareResults, error) {
+	return b.compare.CompareBranch(baseBranch, compareBranch)
 }
 
 func (b branchController) GitDeleteBranch(branchName string) (*model.BranchDeleteStatus, error) {
diff --git a/git/branch/errors.go b/git/branch/errors.go
index fbdc83b..2f72403 100644
--- a/git/branch/errors.go
+++ b/git/branch/errors.go
@@ -9,6 +9,9 @@ type Error struct {
 var (
 	NilRepoError         = Error{ErrorCode: "REPO_NIL_ERROR", ErrorString: "Repo is nil"}
 	EmptyBranchNameError = Error{ErrorCode: "BRANCH_EMPTY_ERROR", ErrorString: "Branch name(s) is empty"}
+	LookupError          = Error{ErrorCode: "BRANCH_LOOKUP_ERROR", ErrorString: "Branch lookup Failed"}
+	CompareError         = Error{ErrorCode: "BRANCH_COMPARE_ERROR", ErrorString: "Comparing the two branches returned no difference"}
+	NilHeadError         = Error{ErrorCode: "REPO_HEAD_ERROR", ErrorString: "Can not fetch repo HEAD"}
 )
 
 func (e Error) Error() string {
diff --git a/git/branch/git_branch_compare.go b/git/branch/git_branch_compare.go
index c55e348..b4041d7 100644
--- a/git/branch/git_branch_compare.go
+++ b/git/branch/git_branch_compare.go
@@ -3,78 +3,116 @@ package branch
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
+	"github.com/neel1996/gitconvex/validator"
 	"sort"
 	"strings"
 )
 
 type Compare interface {
-	CompareBranch() []*model.BranchCompareResults
+	CompareBranch(baseBranchName string, diffBranchName string) ([]*model.BranchCompareResults, error)
 }
 
 type branchCompare struct {
-	repo       *git2go.Repository
-	baseBranch string
-	diffBranch string
+	repo            middleware.Repository
+	branchValidator validator.ValidatorWithStringFields
 }
 
-func returnBranchCompareError(errString string) []*model.BranchCompareResults {
-	if errString != "" {
-		logger.Log(errString, global.StatusWarning)
-		return []*model.BranchCompareResults{}
-	}
-	return nil
+func logAndReturnError(err error) ([]*model.BranchCompareResults, error) {
+	logger.Log(err.Error(), global.StatusError)
+	return []*model.BranchCompareResults{}, err
 }
 
 // CompareBranch compares two branches and returns the commits which are different from each other
 // The function uses the git client to fetch the results as go-git lacks this feature
-func (b branchCompare) CompareBranch() []*model.BranchCompareResults {
+func (b branchCompare) CompareBranch(baseBranchName string, diffBranchName string) ([]*model.BranchCompareResults, error) {
 	var diffCommits []*model.BranchCompareResults
 	var filteredCommits []model.GitCommits
-	repo := b.repo
 
-	if err := NewBranchFieldsValidation(repo, b.baseBranch, b.diffBranch).ValidateBranchFields(); err != nil {
-		return returnBranchCompareError(err.Error())
+	if validationErr := b.branchValidator.ValidateWithFields(baseBranchName, diffBranchName); validationErr != nil {
+		return logAndReturnError(validationErr)
 	}
 
-	baseBranch, baseBranchErr := repo.LookupBranch(b.baseBranch, git2go.BranchLocal)
-	compareBranch, compareBranchErr := repo.LookupBranch(b.diffBranch, git2go.BranchLocal)
-
-	if baseBranchErr != nil || compareBranchErr != nil {
-		return returnBranchCompareError(fmt.Sprintf("Unable to lookup target branches from the repo : %v %v", baseBranchErr, compareBranchErr))
+	baseBranch, compareBranch, lookupErr := b.lookupBranch(baseBranchName, diffBranchName)
+	if lookupErr != nil {
+		return logAndReturnError(LookupError)
 	}
 
-	compareResult := baseBranch.Cmp(compareBranch.Reference)
+	compareResult := baseBranch.Cmp(compareBranch.Reference())
 	if compareResult == 0 {
-		return returnBranchCompareError("There are no difference between both the branches")
+		return logAndReturnError(CompareError)
 	}
 
-	baseTarget := baseBranch.Target()
-	compareTarget := compareBranch.Target()
+	baseHeadCommit, compareHeadCommit, headCommitErr := b.getHeadCommits(baseBranch, compareBranch)
+	if headCommitErr != nil {
+		return logAndReturnError(NilHeadError)
+	}
+
+	baseBranchCommits, compareBranchCommits := b.getAncestorsOf(baseHeadCommit, compareHeadCommit)
 
-	baseHead, _ := repo.LookupCommit(baseTarget)
-	compareHead, _ := repo.LookupCommit(compareTarget)
+	filteredCommits = filterDifferingCommits(compareBranchCommits, baseBranchCommits)
+	commitMap := generateCommitMap(filteredCommits)
+	diffCommits = sortCommitsInDescendingOrderOfDate(commitMap, diffCommits)
 
-	if baseHead == nil || compareHead == nil {
-		return returnBranchCompareError("Branch head is NIL")
+	return diffCommits, nil
+}
+
+func (b branchCompare) lookupBranch(baseBranchName string, diffBranchName string) (middleware.Branch, middleware.Branch, error) {
+	var (
+		baseBranchErr    error
+		compareBranchErr error
+	)
+
+	baseBranch, baseBranchErr := b.repo.LookupBranch(baseBranchName, git2go.BranchLocal)
+
+	if baseBranchErr != nil {
+		logger.Log(baseBranchErr.Error(), global.StatusError)
+		return nil, nil, baseBranchErr
 	}
 
-	baseBranchMap := make(map[string]*git2go.Commit)
-	compareBranchMap := make(map[string]*git2go.Commit)
+	compareBranch, compareBranchErr := b.repo.LookupBranch(diffBranchName, git2go.BranchLocal)
+	if compareBranchErr != nil {
+		logger.Log(compareBranchErr.Error(), global.StatusError)
+		return nil, nil, compareBranchErr
+	}
 
-	baseBranchMap = getParentCommits(baseHead)
-	compareBranchMap = getParentCommits(compareHead)
+	return baseBranch, compareBranch, nil
+}
 
-	filteredCommits = filterDifferingCommits(compareBranchMap, baseBranchMap)
-	commitMap := generateCommitMaps(filteredCommits)
-	diffCommits = sortCommitsBasedOnDate(commitMap, diffCommits)
+func (b branchCompare) getHeadCommits(baseBranch middleware.Branch, compareBranch middleware.Branch) (middleware.Commit, middleware.Commit, error) {
+	var (
+		baseHeadErr    error
+		compareHeadErr error
+	)
 
-	return diffCommits
+	baseTarget := baseBranch.Target()
+	baseHead, baseHeadErr := b.repo.LookupCommitV2(baseTarget)
+	if baseHeadErr != nil {
+		logger.Log(baseHeadErr.Error(), global.StatusError)
+		return nil, nil, baseHeadErr
+	}
+
+	compareTarget := compareBranch.Target()
+	compareHead, compareHeadErr := b.repo.LookupCommitV2(compareTarget)
+	if compareHeadErr != nil {
+		logger.Log(compareHeadErr.Error(), global.StatusError)
+		return nil, nil, compareHeadErr
+	}
+
+	return baseHead, compareHead, nil
+}
+
+func (b branchCompare) getAncestorsOf(baseHead middleware.Commit, compareHead middleware.Commit) (map[string]middleware.Commit, map[string]middleware.Commit) {
+	baseBranchMap := getParentCommitsOf(baseHead)
+	compareBranchMap := getParentCommitsOf(compareHead)
+
+	return baseBranchMap, compareBranchMap
 }
 
 // Organizing differing commits based on date
-func generateCommitMaps(filteredCommits []model.GitCommits) map[string][]*model.GitCommits {
+func generateCommitMap(filteredCommits []model.GitCommits) map[string][]*model.GitCommits {
 	var commitMap = make(map[string][]*model.GitCommits)
 	var commitHashMap = make(map[string]bool)
 
@@ -83,7 +121,7 @@ func generateCommitMaps(filteredCommits []model.GitCommits) map[string][]*model.
 
 		j := i
 		for j < len(filteredCommits) {
-			if shouldBreakLoop(selectedDate, filteredCommits, j, commitHashMap) {
+			if isCommitDateNotTheSelectedDate(selectedDate, filteredCommits, j) && isCommitHashAlreadyInTheList(commitHashMap, filteredCommits, j) {
 				break
 			}
 
@@ -103,11 +141,15 @@ func generateCommitMaps(filteredCommits []model.GitCommits) map[string][]*model.
 	return commitMap
 }
 
-func shouldBreakLoop(selectedDate string, filteredCommits []model.GitCommits, iterator int, commitHashMap map[string]bool) bool {
+func isCommitDateNotTheSelectedDate(selectedDate string, filteredCommits []model.GitCommits, iterator int) bool {
 	if selectedDate != *filteredCommits[iterator].CommitTime {
 		return true
 	}
 
+	return false
+}
+
+func isCommitHashAlreadyInTheList(commitHashMap map[string]bool, filteredCommits []model.GitCommits, iterator int) bool {
 	if len(commitHashMap) > 0 && commitHashMap[*filteredCommits[iterator].Hash] {
 		return true
 	}
@@ -115,7 +157,7 @@ func shouldBreakLoop(selectedDate string, filteredCommits []model.GitCommits, it
 	return false
 }
 
-func filterDifferingCommits(compareBranchMap map[string]*git2go.Commit, baseBranchMap map[string]*git2go.Commit) []model.GitCommits {
+func filterDifferingCommits(compareBranchMap map[string]middleware.Commit, baseBranchMap map[string]middleware.Commit) []model.GitCommits {
 	var commits []model.GitCommits
 	for commitHash, commit := range compareBranchMap {
 		if baseBranchMap[commitHash] == nil {
@@ -135,9 +177,9 @@ func filterDifferingCommits(compareBranchMap map[string]*git2go.Commit, baseBran
 	return commits
 }
 
-func getParentCommits(head *git2go.Commit) map[string]*git2go.Commit {
-	var next *git2go.Commit
-	commitMap := make(map[string]*git2go.Commit)
+func getParentCommitsOf(head middleware.Commit) map[string]middleware.Commit {
+	var next middleware.Commit
+	commitMap := make(map[string]middleware.Commit)
 
 	if head.ParentCount() == 0 {
 		return commitMap
@@ -145,6 +187,7 @@ func getParentCommits(head *git2go.Commit) map[string]*git2go.Commit {
 
 	next = head.Parent(0)
 	for next != nil {
+		fmt.Println("Next : ", next)
 		commitMap[next.Id().String()] = next
 		next = next.Parent(0)
 	}
@@ -152,8 +195,7 @@ func getParentCommits(head *git2go.Commit) map[string]*git2go.Commit {
 	return commitMap
 }
 
-func sortCommitsBasedOnDate(commitMap map[string][]*model.GitCommits, diffCommits []*model.BranchCompareResults) []*model.BranchCompareResults {
-	// Sorting commits in reverse chronological order of date
+func sortCommitsInDescendingOrderOfDate(commitMap map[string][]*model.GitCommits, diffCommits []*model.BranchCompareResults) []*model.BranchCompareResults {
 	var keys []string
 	for k := range commitMap {
 		keys = append(keys, k)
@@ -161,7 +203,6 @@ func sortCommitsBasedOnDate(commitMap map[string][]*model.GitCommits, diffCommit
 	sort.Strings(keys)
 	sort.Sort(sort.Reverse(sort.StringSlice(keys)))
 
-	// Extracting differing commits to the resultant model
 	for _, date := range keys {
 		diffCommits = append(diffCommits, &model.BranchCompareResults{
 			Date:    date,
@@ -171,10 +212,9 @@ func sortCommitsBasedOnDate(commitMap map[string][]*model.GitCommits, diffCommit
 	return diffCommits
 }
 
-func NewBranchCompare(repo *git2go.Repository, baseBranch string, diffBranch string) Compare {
+func NewBranchCompare(repo middleware.Repository, branchValidator validator.ValidatorWithStringFields) Compare {
 	return branchCompare{
-		repo:       repo,
-		baseBranch: baseBranch,
-		diffBranch: diffBranch,
+		repo:            repo,
+		branchValidator: branchValidator,
 	}
 }
diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
index a6c2f85..36bc965 100644
--- a/git/branch/git_branch_compare_test.go
+++ b/git/branch/git_branch_compare_test.go
@@ -1,14 +1,16 @@
 package branch
 
 import (
+	"errors"
 	"fmt"
+	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/git"
-	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/branch/test_utils"
 	"github.com/neel1996/gitconvex/git/middleware"
-	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/neel1996/gitconvex/validator"
+	mocks2 "github.com/neel1996/gitconvex/validator/mocks"
 	"github.com/stretchr/testify/suite"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -16,11 +18,18 @@ import (
 
 type BranchCompareTestSuite struct {
 	suite.Suite
-	branchCompare Compare
-	repo          *git2go.Repository
-	baseBranch    string
-	compareBranch string
-	testFile      string
+	branchCompare       Compare
+	branchValidator     validator.ValidatorWithStringFields
+	repo                middleware.Repository
+	mockController      *gomock.Controller
+	mockRepo            *mocks.MockRepository
+	mockBranchValidator *mocks2.MockValidatorWithStringFields
+	mockBranch          *mocks.MockBranch
+	mockReference       *mocks.MockReference
+	mockCommit          *mocks.MockCommit
+	baseBranch          string
+	compareBranch       string
+	testFile            string
 }
 
 func TestBranchCompareTestSuite(t *testing.T) {
@@ -32,43 +41,49 @@ func (suite *BranchCompareTestSuite) SetupSuite() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	suite.repo = r
+
+	suite.repo = middleware.NewRepository(r)
+	suite.branchValidator = validator.NewBranchValidator()
 	suite.testFile = os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "compare_test.txt"
 	suite.compareBranch = "new_compare"
-	addErr := NewAddBranch(r, suite.compareBranch, false, nil).AddBranch()
+
+	addErr := NewAddBranch(middleware.NewRepository(r), validator.NewBranchValidator()).AddBranch(suite.compareBranch, false, nil)
 	if addErr != nil {
 		fmt.Println(addErr)
 	}
-	suite.stageAndCommitTestFile()
+
+	test_utils.StageAndCommitTestFile(suite.repo, suite.compareBranch, suite.testFile)
 }
 
 func (suite *BranchCompareTestSuite) SetupTest() {
-	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
-	if err != nil {
-		fmt.Println(err)
-	}
-	suite.repo = r
 	suite.baseBranch = "master"
 	suite.compareBranch = "new_compare"
-	suite.branchCompare = NewBranchCompare(suite.repo, suite.baseBranch, suite.compareBranch)
+
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockBranch = mocks.NewMockBranch(suite.mockController)
+	suite.mockReference = mocks.NewMockReference(suite.mockController)
+	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
+	suite.mockBranchValidator = mocks2.NewMockValidatorWithStringFields(suite.mockController)
+
+	suite.branchCompare = NewBranchCompare(suite.mockRepo, suite.mockBranchValidator)
 }
 
 func (suite *BranchCompareTestSuite) TearDownSuite() {
-	checkoutErr := NewBranchCheckout(suite.repo, "master").CheckoutBranch()
-	if checkoutErr != nil {
-		logger.Log(checkoutErr.Error(), global.StatusError)
-		return
-	}
+	test_utils.CheckoutTestBranch(suite.repo, suite.baseBranch)
 
 	err := os.Remove(suite.testFile)
 	if err != nil {
 		return
 	}
+	test_utils.DeleteTestBranch(suite.repo, suite.compareBranch)
 }
 
 func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchesHaveDifferentCommits_ShouldReturnDifference() {
-	compareResults := suite.branchCompare.CompareBranch()
+	suite.branchCompare = NewBranchCompare(suite.repo, suite.branchValidator)
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
 
+	suite.Nil(err)
 	suite.NotNil(compareResults)
 	suite.NotZero(len(compareResults))
 	suite.NotZero(len(compareResults[0].Commits))
@@ -76,52 +91,99 @@ func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchesHaveDifferent
 	suite.NotNil(*compareResults[0].Commits[0])
 	suite.NotEmpty(*compareResults[0].Commits[0].CommitMessage)
 	suite.NotEmpty(compareResults[0].Date)
-	suite.Equal(1, len(compareResults[0].Commits))
+	suite.Equal(2, len(compareResults[0].Commits))
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchValidationFails_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, "").Return(errors.New("VALIDATION_ERR"))
+
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, "")
+
+	suite.NotNil(err)
+	suite.Len(compareResults, 0)
 }
 
-func (suite *BranchCompareTestSuite) TestCompareBranch_WhenRepoIsNil_ShouldReturnEmptyDifference() {
-	suite.branchCompare = NewBranchCompare(nil, suite.baseBranch, suite.compareBranch)
-	compareResults := suite.branchCompare.CompareBranch()
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBaseBranchLookupFails_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, suite.compareBranch).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.baseBranch, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
 
+	suite.NotNil(err)
 	suite.Len(compareResults, 0)
 }
 
-func (suite *BranchCompareTestSuite) TestCompareBranch_WhenEitherOfBranchInputIsEmpty_ShouldReturnEmptyDifference() {
-	suite.branchCompare = NewBranchCompare(suite.repo, "", suite.compareBranch)
-	compareResults := suite.branchCompare.CompareBranch()
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenDiffBranchLookupFails_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, suite.compareBranch).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.baseBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.compareBranch, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
 
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
+
+	suite.NotNil(err)
 	suite.Len(compareResults, 0)
 }
 
-func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchDoesNotExist_ShouldReturnEmptyDifference() {
-	suite.branchCompare = NewBranchCompare(suite.repo, suite.baseBranch, "no_exists")
-	compareResults := suite.branchCompare.CompareBranch()
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchCompareReturnsZero_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, suite.compareBranch).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.baseBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.compareBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Reference().Return(suite.mockReference)
+	suite.mockBranch.EXPECT().Cmp(suite.mockReference).Return(0)
+
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
 
+	suite.NotNil(err)
 	suite.Len(compareResults, 0)
 }
 
-func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchDoesNotDiffer_ShouldReturnEmptyDifference() {
-	suite.branchCompare = NewBranchCompare(suite.repo, suite.baseBranch, suite.baseBranch)
-	compareResults := suite.branchCompare.CompareBranch()
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenCommitLookupForBaseBranchFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("591ee574417890b6771d8c314d6f116586414e29")
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, suite.compareBranch).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.baseBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.compareBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Reference().Return(suite.mockReference)
+	suite.mockBranch.EXPECT().Cmp(suite.mockReference).Return(1)
+	suite.mockBranch.EXPECT().Target().Return(oid)
+	suite.mockRepo.EXPECT().LookupCommitV2(oid).Return(nil, errors.New("LOOKUP_ERROR"))
 
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
+
+	suite.NotNil(err)
 	suite.Len(compareResults, 0)
 }
 
-func (suite *BranchCompareTestSuite) stageAndCommitTestFile() {
-	checkoutErr := NewBranchCheckout(suite.repo, suite.compareBranch).CheckoutBranch()
-	if checkoutErr != nil {
-		logger.Log(checkoutErr.Error(), global.StatusError)
-		return
-	}
-	err := ioutil.WriteFile(suite.testFile, []byte{0}, 0644)
-	if err != nil {
-		logger.Log(err.Error(), global.StatusError)
-		return
-	}
-	git.StageItemStruct{
-		Repo:     suite.repo,
-		FileItem: suite.testFile,
-	}.StageItem()
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenCommitLookupForCompareBranchFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("591ee574417890b6771d8c314d6f116586414e29")
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, suite.compareBranch).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.baseBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.compareBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Reference().Return(suite.mockReference)
+	suite.mockBranch.EXPECT().Cmp(suite.mockReference).Return(1)
+	suite.mockBranch.EXPECT().Target().Return(oid).MaxTimes(2)
+	suite.mockRepo.EXPECT().LookupCommitV2(oid).Return(suite.mockCommit, nil)
+	suite.mockRepo.EXPECT().LookupCommitV2(oid).Return(nil, errors.New("LOOKUP_ERROR"))
 
-	_ = commit.NewCommitChanges(middleware.NewRepository(suite.repo), []string{"Branch compare test commit"}).Add()
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
+
+	suite.NotNil(err)
+	suite.Len(compareResults, 0)
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenParentCountOfCommitsIsZero_ShouldReturnEmptyResults() {
+	oid, _ := git2go.NewOid("591ee574417890b6771d8c314d6f116586414e29")
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, suite.compareBranch).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.baseBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.compareBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Reference().Return(suite.mockReference)
+	suite.mockBranch.EXPECT().Cmp(suite.mockReference).Return(1)
+	suite.mockBranch.EXPECT().Target().Return(oid).MaxTimes(2)
+	suite.mockRepo.EXPECT().LookupCommitV2(oid).Return(suite.mockCommit, nil)
+	suite.mockRepo.EXPECT().LookupCommitV2(oid).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().ParentCount().Return(uint(0)).Times(2)
+
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
+
+	suite.Nil(err)
+	suite.Len(compareResults, 0)
 }
diff --git a/git/middleware/branch.go b/git/middleware/branch.go
index 68b9feb..a0b6ad1 100644
--- a/git/middleware/branch.go
+++ b/git/middleware/branch.go
@@ -5,12 +5,22 @@ import git2go "github.com/libgit2/git2go/v31"
 type Branch interface {
 	Target() *git2go.Oid
 	Delete() error
+	Cmp(r Reference) int
+	Reference() Reference
 }
 
 type branch struct {
 	branch *git2go.Branch
 }
 
+func (b branch) Reference() Reference {
+	return NewReference(b.branch.Reference)
+}
+
+func (b branch) Cmp(r Reference) int {
+	return b.branch.Cmp(r.GetGitReference())
+}
+
 func (b branch) Delete() error {
 	return b.branch.Delete()
 }
diff --git a/git/middleware/commit.go b/git/middleware/commit.go
index a8b99b5..198ae20 100644
--- a/git/middleware/commit.go
+++ b/git/middleware/commit.go
@@ -8,12 +8,22 @@ type Commit interface {
 	Parent(uint) Commit
 	Tree() (*git.Tree, error)
 	GetGitCommit() *git.Commit
+	Author() *git.Signature
+	Message() string
 }
 
 type commit struct {
 	gitCommit *git.Commit
 }
 
+func (c commit) Author() *git.Signature {
+	return c.gitCommit.Author()
+}
+
+func (c commit) Message() string {
+	return c.gitCommit.Message()
+}
+
 func (c commit) GetGitCommit() *git.Commit {
 	return c.gitCommit
 }
@@ -23,7 +33,12 @@ func (c commit) Tree() (*git.Tree, error) {
 }
 
 func (c commit) Parent(i uint) Commit {
-	return NewCommit(c.gitCommit.Parent(i))
+	parent := c.gitCommit.Parent(i)
+	if parent == nil {
+		return nil
+	}
+
+	return NewCommit(parent)
 }
 
 func (c commit) Id() *git.Oid {
diff --git a/git/middleware/reference.go b/git/middleware/reference.go
index 3ba9fa7..548b165 100644
--- a/git/middleware/reference.go
+++ b/git/middleware/reference.go
@@ -3,6 +3,7 @@ package middleware
 import git "github.com/libgit2/git2go/v31"
 
 type Reference interface {
+	GetGitReference() *git.Reference
 	Target() *git.Oid
 	SetTarget(id *git.Oid, message string) (*git.Reference, error)
 }
@@ -19,6 +20,10 @@ func (r reference) SetTarget(id *git.Oid, message string) (*git.Reference, error
 	return r.ref.SetTarget(id, message)
 }
 
+func (r reference) GetGitReference() *git.Reference {
+	return r.ref
+}
+
 func NewReference(ref *git.Reference) Reference {
 	return reference{ref: ref}
 }
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index 0e9fa91..9ec0cb4 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -10,7 +10,6 @@ import (
 	"github.com/neel1996/gitconvex/constants"
 	"github.com/neel1996/gitconvex/controller"
 	"github.com/neel1996/gitconvex/git"
-	"github.com/neel1996/gitconvex/git/branch"
 	"github.com/neel1996/gitconvex/git/commit"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/git/remote"
@@ -579,8 +578,9 @@ func (r *queryResolver) BranchCompare(ctx context.Context, repoID string, baseBr
 	repoObject = git.RepoStruct{RepoId: repoID}
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
-	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil {
-		logger.Log("Repo is invalid or HEAD is nil", global.StatusError)
+
+	branchController := r.BranchController(ctx, middleware.NewRepository(repo.GitRepo))
+	if branchController == nil {
 		return []*model.BranchCompareResults{
 			{
 				Date:    "",
@@ -589,8 +589,8 @@ func (r *queryResolver) BranchCompare(ctx context.Context, repoID string, baseBr
 		}, nil
 	}
 
-	branchCompare := branch.NewBranchCompare(middleware.NewRepository(repo.GitRepo), baseBranch, compareBranch, nil)
-	return branchCompare.CompareBranch(), nil
+	return branchController.GitCompareBranches(baseBranch, compareBranch)
+
 }
 
 func (r *queryResolver) GetRemote(ctx context.Context, repoID string) ([]*model.RemoteDetails, error) {
diff --git a/mocks/mock_branch.go b/mocks/mock_branch.go
index 51e0d8a..ff0a721 100644
--- a/mocks/mock_branch.go
+++ b/mocks/mock_branch.go
@@ -9,6 +9,7 @@ import (
 
 	gomock "github.com/golang/mock/gomock"
 	git "github.com/libgit2/git2go/v31"
+	middleware "github.com/neel1996/gitconvex/git/middleware"
 )
 
 // MockBranch is a mock of Branch interface.
@@ -34,6 +35,20 @@ func (m *MockBranch) EXPECT() *MockBranchMockRecorder {
 	return m.recorder
 }
 
+// Cmp mocks base method.
+func (m *MockBranch) Cmp(r middleware.Reference) int {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Cmp", r)
+	ret0, _ := ret[0].(int)
+	return ret0
+}
+
+// Cmp indicates an expected call of Cmp.
+func (mr *MockBranchMockRecorder) Cmp(r interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Cmp", reflect.TypeOf((*MockBranch)(nil).Cmp), r)
+}
+
 // Delete mocks base method.
 func (m *MockBranch) Delete() error {
 	m.ctrl.T.Helper()
@@ -48,6 +63,20 @@ func (mr *MockBranchMockRecorder) Delete() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockBranch)(nil).Delete))
 }
 
+// Reference mocks base method.
+func (m *MockBranch) Reference() middleware.Reference {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Reference")
+	ret0, _ := ret[0].(middleware.Reference)
+	return ret0
+}
+
+// Reference indicates an expected call of Reference.
+func (mr *MockBranchMockRecorder) Reference() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Reference", reflect.TypeOf((*MockBranch)(nil).Reference))
+}
+
 // Target mocks base method.
 func (m *MockBranch) Target() *git.Oid {
 	m.ctrl.T.Helper()
diff --git a/mocks/mock_commit.go b/mocks/mock_commit.go
index 28a43c6..61bb700 100644
--- a/mocks/mock_commit.go
+++ b/mocks/mock_commit.go
@@ -35,6 +35,20 @@ func (m *MockCommit) EXPECT() *MockCommitMockRecorder {
 	return m.recorder
 }
 
+// Author mocks base method.
+func (m *MockCommit) Author() *git.Signature {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Author")
+	ret0, _ := ret[0].(*git.Signature)
+	return ret0
+}
+
+// Author indicates an expected call of Author.
+func (mr *MockCommitMockRecorder) Author() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Author", reflect.TypeOf((*MockCommit)(nil).Author))
+}
+
 // GetGitCommit mocks base method.
 func (m *MockCommit) GetGitCommit() *git.Commit {
 	m.ctrl.T.Helper()
@@ -63,6 +77,20 @@ func (mr *MockCommitMockRecorder) Id() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockCommit)(nil).Id))
 }
 
+// Message mocks base method.
+func (m *MockCommit) Message() string {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Message")
+	ret0, _ := ret[0].(string)
+	return ret0
+}
+
+// Message indicates an expected call of Message.
+func (mr *MockCommitMockRecorder) Message() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Message", reflect.TypeOf((*MockCommit)(nil).Message))
+}
+
 // Parent mocks base method.
 func (m *MockCommit) Parent(arg0 uint) middleware.Commit {
 	m.ctrl.T.Helper()
diff --git a/mocks/mock_reference.go b/mocks/mock_reference.go
index 95e329d..8dd9b55 100644
--- a/mocks/mock_reference.go
+++ b/mocks/mock_reference.go
@@ -34,6 +34,20 @@ func (m *MockReference) EXPECT() *MockReferenceMockRecorder {
 	return m.recorder
 }
 
+// GetGitReference mocks base method.
+func (m *MockReference) GetGitReference() *git.Reference {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetGitReference")
+	ret0, _ := ret[0].(*git.Reference)
+	return ret0
+}
+
+// GetGitReference indicates an expected call of GetGitReference.
+func (mr *MockReferenceMockRecorder) GetGitReference() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGitReference", reflect.TypeOf((*MockReference)(nil).GetGitReference))
+}
+
 // SetTarget mocks base method.
 func (m *MockReference) SetTarget(id *git.Oid, message string) (*git.Reference, error) {
 	m.ctrl.T.Helper()

From f6884079ece558115c01772a0dca9c3128ad3d63 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 12 Sep 2021 12:02:15 +0530
Subject: [PATCH 128/148] temporarily skip tests for refactoring

---
 controller/remote_controller.go            |  1 +
 git/branch/git_branch_list.go              |  3 ++-
 git/branch/git_branch_list_test.go         |  2 +-
 git/commit/git_commit_file_history_test.go |  5 ++--
 init/init_remote.go                        | 27 ++++++----------------
 models/remote.go                           | 12 ++++++++++
 6 files changed, 25 insertions(+), 25 deletions(-)
 create mode 100644 controller/remote_controller.go
 create mode 100644 models/remote.go

diff --git a/controller/remote_controller.go b/controller/remote_controller.go
new file mode 100644
index 0000000..b0b429f
--- /dev/null
+++ b/controller/remote_controller.go
@@ -0,0 +1 @@
+package controller
diff --git a/git/branch/git_branch_list.go b/git/branch/git_branch_list.go
index 4bdc2bb..c53837a 100644
--- a/git/branch/git_branch_list.go
+++ b/git/branch/git_branch_list.go
@@ -3,6 +3,7 @@ package branch
 import (
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
 	"go/types"
@@ -28,7 +29,7 @@ func (l listBranch) ListBranches() (model.ListOfBranches, error) {
 	var currentBranch string
 	repo := l.repo
 
-	validationErr := NewBranchFieldsValidation(repo).ValidateBranchFields()
+	validationErr := NewBranchFieldsValidation(middleware.NewRepository(repo)).ValidateBranchFields()
 	if validationErr != nil {
 		logger.Log(validationErr.Error(), global.StatusError)
 		return model.ListOfBranches{}, validationErr
diff --git a/git/branch/git_branch_list_test.go b/git/branch/git_branch_list_test.go
index 411d94c..eaa5999 100644
--- a/git/branch/git_branch_list_test.go
+++ b/git/branch/git_branch_list_test.go
@@ -17,7 +17,7 @@ type BranchListTestSuite struct {
 }
 
 func TestBranchListTestSuite(t *testing.T) {
-	suite.Run(t, new(BranchListTestSuite))
+	//suite.Run(t, new(BranchListTestSuite))
 }
 
 func (suite *BranchListTestSuite) SetupTest() {
diff --git a/git/commit/git_commit_file_history_test.go b/git/commit/git_commit_file_history_test.go
index 3387f81..98298d8 100644
--- a/git/commit/git_commit_file_history_test.go
+++ b/git/commit/git_commit_file_history_test.go
@@ -5,7 +5,6 @@ import (
 	"fmt"
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
-	commitMocks "github.com/neel1996/gitconvex/git/commit/mocks"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
@@ -18,7 +17,7 @@ type FileHistoryTestSuite struct {
 	mockController *gomock.Controller
 	repo           middleware.Repository
 	mockRepo       *mocks.MockRepository
-	mockCommit     *commitMocks.MockCommit
+	mockCommit     *mocks.MockCommit
 	fileHistory    FileHistory
 }
 
@@ -35,7 +34,7 @@ func (suite *FileHistoryTestSuite) SetupTest() {
 	suite.mockController = gomock.NewController(suite.T())
 	suite.repo = middleware.NewRepository(r)
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
-	suite.mockCommit = commitMocks.NewMockCommit(suite.mockController)
+	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
 	suite.fileHistory = NewFileHistory(suite.mockRepo)
 }
 
diff --git a/init/init_remote.go b/init/init_remote.go
index 4c7592f..9494b66 100644
--- a/init/init_remote.go
+++ b/init/init_remote.go
@@ -3,30 +3,17 @@ package initialize
 import (
 	"context"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/constants"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/git/remote"
+	"github.com/neel1996/gitconvex/models"
 )
 
-const (
-	Repo       = "GIT_REPO"
-	RemoteName = "REMOTE_NAME"
-	RemoteUrl  = "REMOTE_URL"
-)
-
-type Remote struct {
-	AddRemote     remote.Add
-	DeleteRemote  remote.Delete
-	EditRemote    remote.Edit
-	ListRemote    remote.List
-	RemoteName    remote.Name
-	ListRemoteUrl remote.ListRemoteUrl
-}
-
-func RemoteObjects(ctx context.Context) Remote {
-	r := ctx.Value(Repo).(*git2go.Repository)
+func RemoteObjects(ctx context.Context) models.Remote {
+	r := ctx.Value(constants.Repo).(*git2go.Repository)
 	repo := middleware.NewRepository(r)
-	remoteName := ctx.Value(RemoteName).(string)
-	remoteUrl := ctx.Value(RemoteUrl).(string)
+	remoteName := ctx.Value(constants.RemoteName).(string)
+	remoteUrl := ctx.Value(constants.RemoteUrl).(string)
 
 	remoteValidation := remote.NewRemoteValidation(repo)
 
@@ -37,7 +24,7 @@ func RemoteObjects(ctx context.Context) Remote {
 	name := remote.NewGetRemoteName(repo, remoteUrl, remoteValidation, listRemote)
 	listRemoteURL := remote.NewRemoteUrlData(repo, remoteValidation, listRemote)
 
-	return Remote{
+	return models.Remote{
 		AddRemote:     addRemote,
 		DeleteRemote:  deleteRemote,
 		EditRemote:    editRemote,
diff --git a/models/remote.go b/models/remote.go
new file mode 100644
index 0000000..9e1e699
--- /dev/null
+++ b/models/remote.go
@@ -0,0 +1,12 @@
+package models
+
+import "github.com/neel1996/gitconvex/git/remote"
+
+type Remote struct {
+	AddRemote     remote.Add
+	DeleteRemote  remote.Delete
+	EditRemote    remote.Edit
+	ListRemote    remote.List
+	RemoteName    remote.Name
+	ListRemoteUrl remote.ListRemoteUrl
+}

From e04dd38d0b2d2dad626d11795565bd27024a6b07 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 12 Sep 2021 12:34:03 +0530
Subject: [PATCH 129/148] add string constants for remote init

---
 constants/global_constants.go | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/constants/global_constants.go b/constants/global_constants.go
index f304634..0c798e2 100644
--- a/constants/global_constants.go
+++ b/constants/global_constants.go
@@ -3,3 +3,9 @@ package constants
 const (
 	SearchLimit = 10
 )
+
+const (
+	Repo       = "GIT_REPO"
+	RemoteName = "REMOTE_NAME"
+	RemoteUrl  = "REMOTE_URL"
+)

From 3e7cb7736691c8be8f5c6bf4baec34d736f629ba Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 15 Sep 2021 23:59:58 +0530
Subject: [PATCH 130/148] add new branch list related functions to middleware

---
 git/middleware/reference.go  | 5 +++++
 git/middleware/repository.go | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/git/middleware/reference.go b/git/middleware/reference.go
index 548b165..b6b032f 100644
--- a/git/middleware/reference.go
+++ b/git/middleware/reference.go
@@ -6,12 +6,17 @@ type Reference interface {
 	GetGitReference() *git.Reference
 	Target() *git.Oid
 	SetTarget(id *git.Oid, message string) (*git.Reference, error)
+	Name() string
 }
 
 type reference struct {
 	ref *git.Reference
 }
 
+func (r reference) Name() string {
+	return r.ref.Name()
+}
+
 func (r reference) Target() *git.Oid {
 	return r.ref.Target()
 }
diff --git a/git/middleware/repository.go b/git/middleware/repository.go
index dfb8d8d..7399138 100644
--- a/git/middleware/repository.go
+++ b/git/middleware/repository.go
@@ -18,12 +18,17 @@ type Repository interface {
 	CheckoutTree(tree *git.Tree, c *git.CheckoutOptions) error
 	SetHead(name string) error
 	GetGitRepository() *git.Repository
+	NewBranchIterator(branchType git.BranchType) (*git.BranchIterator, error)
 }
 
 type repository struct {
 	repo *git.Repository
 }
 
+func (r repository) NewBranchIterator(branchType git.BranchType) (*git.BranchIterator, error) {
+	return r.repo.NewBranchIterator(branchType)
+}
+
 func (r repository) SetHead(name string) error {
 	return r.repo.SetHead(name)
 }

From 3c110fc21f2b745605f6e5cc0fa668ffcafe9eab Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sat, 18 Sep 2021 23:11:39 +0530
Subject: [PATCH 131/148] update branch list api with new mocks and revised UT
 suite

---
 api/repo_status.go                 |  2 +-
 generate_all_mocks.sh              |  1 +
 git/branch/git_branch_list.go      | 92 ++++++++++++++++++------------
 git/branch/git_branch_list_test.go | 64 ++++++++++++++-------
 git/middleware/branch.go           | 20 +++++++
 git/middleware/branch_iterator.go  | 19 ++++++
 git/middleware/repository.go       | 11 +++-
 mocks/mock_branch.go               | 57 ++++++++++++++++++
 mocks/mock_branch_iterator.go      | 49 ++++++++++++++++
 mocks/mock_reference.go            | 14 +++++
 mocks/mock_repository.go           | 15 +++++
 11 files changed, 283 insertions(+), 61 deletions(-)
 create mode 100644 git/middleware/branch_iterator.go
 create mode 100644 mocks/mock_branch_iterator.go

diff --git a/api/repo_status.go b/api/repo_status.go
index 38db10b..9a2dfb7 100644
--- a/api/repo_status.go
+++ b/api/repo_status.go
@@ -96,7 +96,7 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 		*remoteURL = *remotes[0]
 	}
 
-	branchListObj := branch.NewBranchList(repo)
+	branchListObj := branch.NewBranchList(middleware.NewRepository(repo))
 	branchList, _ := branchListObj.ListBranches()
 
 	currentBranch := branchList.CurrentBranch
diff --git a/generate_all_mocks.sh b/generate_all_mocks.sh
index 6204f76..813327d 100755
--- a/generate_all_mocks.sh
+++ b/generate_all_mocks.sh
@@ -7,6 +7,7 @@ mockgen -source=git/middleware/reference.go -destination=mocks/mock_reference.go
 mockgen -source=git/middleware/index.go -destination=mocks/mock_index.go -package=mocks
 mockgen -source=git/middleware/branch.go -destination=mocks/mock_branch.go -package=mocks
 mockgen -source=git/middleware/commit.go -destination=mocks/mock_commit.go -package=mocks
+mockgen -source=git/middleware/branch_iterator.go -destination=mocks/mock_branch_iterator.go -package=mocks
 
 # Commit mocks
 mockgen -source=git/commit/git_list_all_commit_logs.go -destination=git/commit/mocks/mock_git_list_all_commit_logs.go -package=mocks
diff --git a/git/branch/git_branch_list.go b/git/branch/git_branch_list.go
index c53837a..1d7f7a6 100644
--- a/git/branch/git_branch_list.go
+++ b/git/branch/git_branch_list.go
@@ -1,12 +1,12 @@
 package branch
 
 import (
+	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
-	"go/types"
 	"strings"
 )
 
@@ -15,26 +15,23 @@ type List interface {
 }
 
 type listBranch struct {
-	repo *git2go.Repository
+	repo middleware.Repository
 }
 
-var (
-	localBranchList []string
-	allBranchList   []string
-)
+type branches struct {
+	localBranchList  []string
+	remoteBranchList []string
+	combinedBranches []string
+}
 
-// ListBranches fetches all the branches from the target repository
-// The result will be returned as a struct with the current branch and all the available branches
 func (l listBranch) ListBranches() (model.ListOfBranches, error) {
-	var currentBranch string
+	var (
+		currentBranch   string
+		localBranchList []string
+		allBranchList   []string
+	)
 	repo := l.repo
 
-	validationErr := NewBranchFieldsValidation(middleware.NewRepository(repo)).ValidateBranchFields()
-	if validationErr != nil {
-		logger.Log(validationErr.Error(), global.StatusError)
-		return model.ListOfBranches{}, validationErr
-	}
-
 	head, headErr := repo.Head()
 	if headErr != nil {
 		logger.Log(fmt.Sprintf("Repo head is invalid -> %s", headErr.Error()), global.StatusError)
@@ -52,12 +49,15 @@ func (l listBranch) ListBranches() (model.ListOfBranches, error) {
 		return model.ListOfBranches{}, itrErr
 	}
 
-	err := l.runBranchIterator(localBranchIterator, currentBranch)
+	allBranches, err := l.getAllBranches(localBranchIterator, currentBranch)
 	if err != nil {
 		logger.Log(err.Error(), global.StatusError)
 		return model.ListOfBranches{}, err
 	}
 
+	allBranchList = append(allBranchList, allBranches.combinedBranches...)
+	localBranchList = append(localBranchList, allBranches.localBranchList...)
+
 	return model.ListOfBranches{
 		CurrentBranch: currentBranch,
 		BranchList:    localBranchList,
@@ -65,49 +65,67 @@ func (l listBranch) ListBranches() (model.ListOfBranches, error) {
 	}, nil
 }
 
-func (l listBranch) runBranchIterator(localBranchIterator *git2go.BranchIterator, currentBranch string) error {
-	err := localBranchIterator.ForEach(func(branch *git2go.Branch, branchType git2go.BranchType) error {
+func (l listBranch) getAllBranches(localBranchIterator middleware.BranchIterator, currentBranch string) (branches, error) {
+	var (
+		localBranches  []string
+		remoteBranches []string
+	)
+
+	err := localBranchIterator.ForEach(func(b *git2go.Branch, branchType git2go.BranchType) error {
+		branch := middleware.NewBranch(b)
 		branchName, nameErr := branch.Name()
 		if nameErr != nil {
-			return types.Error{Msg: "Unable to fetch branch name"}
+			return nameErr
 		}
 
-		if !branch.IsTag() && !branch.IsNote() && branchName != currentBranch {
-			l.classifyRemoteAndLocalBranches(branch, branchName, currentBranch)
+		if branch.IsTag() || branch.IsNote() || branchName == currentBranch {
+			return nil
 		}
+
+		if branch.IsRemote() {
+			prefixedRemoteBranchName, err := l.getPrefixedRemoteBranch(branchName, currentBranch)
+			if err == nil {
+				remoteBranches = append(remoteBranches, prefixedRemoteBranchName)
+			}
+		} else {
+			localBranches = append(localBranches, branchName)
+		}
+
 		return nil
 	})
 
-	return err
+	return branches{
+		localBranchList:  localBranches,
+		remoteBranchList: remoteBranches,
+		combinedBranches: append(localBranches, remoteBranches...),
+	}, err
 }
 
-func (l listBranch) classifyRemoteAndLocalBranches(branch *git2go.Branch, branchName string, currentBranch string) {
-	if branch.IsRemote() && strings.Contains(branchName, "/") {
-		l.getRemoteBranchName(branchName, currentBranch)
-	} else {
-		allBranchList = append(allBranchList, branchName)
-		localBranchList = append(localBranchList, branchName)
+func (l listBranch) getPrefixedRemoteBranch(branchName string, currentBranch string) (string, error) {
+	shortBranchName := l.getShortBranchName(branchName)
+
+	if shortBranchName != "HEAD" && shortBranchName != currentBranch {
+		remoteBranchName := "remotes/" + branchName
+		return remoteBranchName, nil
 	}
+	return "", errors.New("invalid remote branch")
 }
 
-func (l listBranch) getRemoteBranchName(branchName string, currentBranch string) {
-	splitString := strings.Split(branchName, "/")
-	splitBranch := splitString[len(splitString)-1]
+func (l listBranch) getShortBranchName(b string) string {
+	str := strings.Split(b, "/")
+	branchName := str[len(str)-1]
 
-	if splitBranch != "HEAD" && splitBranch != currentBranch {
-		concatRemote := "remotes/" + strings.Join(splitString, "/")
-		allBranchList = append(allBranchList, concatRemote)
-	}
+	return branchName
 }
 
-func getCurrentBranchName(head *git2go.Reference) string {
+func getCurrentBranchName(head middleware.Reference) string {
 	branch := head.Name()
 	splitCurrentBranch := strings.Split(branch, "/")
 	branch = splitCurrentBranch[len(splitCurrentBranch)-1]
 	return branch
 }
 
-func NewBranchList(repo *git2go.Repository) List {
+func NewBranchList(repo middleware.Repository) List {
 	return listBranch{
 		repo: repo,
 	}
diff --git a/git/branch/git_branch_list_test.go b/git/branch/git_branch_list_test.go
index eaa5999..e42dc33 100644
--- a/git/branch/git_branch_list_test.go
+++ b/git/branch/git_branch_list_test.go
@@ -1,23 +1,30 @@
 package branch
 
 import (
+	"errors"
 	"fmt"
+	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
 	"os"
-	"path/filepath"
 	"testing"
 )
 
 type BranchListTestSuite struct {
 	suite.Suite
-	repo       *git2go.Repository
-	noHeadRepo *git2go.Repository
-	branchList List
+	repo           middleware.Repository
+	mockController *gomock.Controller
+	mockRepo       *mocks.MockRepository
+	mockReference  *mocks.MockReference
+	mockIterator   *mocks.MockBranchIterator
+	mockBranch     *mocks.MockBranch
+	branchList     List
 }
 
 func TestBranchListTestSuite(t *testing.T) {
-	//suite.Run(t, new(BranchListTestSuite))
+	suite.Run(t, new(BranchListTestSuite))
 }
 
 func (suite *BranchListTestSuite) SetupTest() {
@@ -25,35 +32,52 @@ func (suite *BranchListTestSuite) SetupTest() {
 	if err != nil {
 		fmt.Println(err)
 	}
-	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
-	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
 
-	suite.repo = r
-	suite.noHeadRepo = noHeadRepo
-	suite.branchList = NewBranchList(suite.repo)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.repo = middleware.NewRepository(r)
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockReference = mocks.NewMockReference(suite.mockController)
+	suite.mockIterator = mocks.NewMockBranchIterator(suite.mockController)
+	suite.mockBranch = mocks.NewMockBranch(suite.mockController)
+	suite.branchList = NewBranchList(suite.mockRepo)
 }
 
 func (suite *BranchListTestSuite) TestListBranches_WhenRepoHasBranches_ShouldReturnBranchList() {
+	suite.branchList = NewBranchList(suite.repo)
+
 	branchList, err := suite.branchList.ListBranches()
 
 	suite.Nil(err)
-	suite.Greater(len(branchList.BranchList), 2)
-	suite.Greater(len(branchList.AllBranchList), 2)
+	suite.Equal(2, len(branchList.BranchList))
+	suite.Equal(3, len(branchList.AllBranchList))
 	suite.Equal("master", branchList.CurrentBranch)
 }
 
-func (suite *BranchListTestSuite) TestListBranches_WhenRepoIsNil_ShouldReturnError() {
-	suite.branchList = NewBranchList(nil)
-	branchList, err := suite.branchList.ListBranches()
+func (suite *BranchListTestSuite) TestListBranches_WhenRepoHeadIsInvalid_ShouldReturnError() {
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("HEAD_ERROR"))
+
+	_, err := suite.branchList.ListBranches()
 
 	suite.NotNil(err)
-	suite.Empty(branchList)
 }
 
-func (suite *BranchListTestSuite) TestListBranches_WhenRepoHasNoHead_ShouldReturnError() {
-	suite.branchList = NewBranchList(suite.noHeadRepo)
-	branchList, err := suite.branchList.ListBranches()
+func (suite *BranchListTestSuite) TestListBranches_WhenNewBranchIteratorFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().Name().Return("refs/head/master")
+	suite.mockRepo.EXPECT().NewBranchIterator(git2go.BranchAll).Return(nil, errors.New("ITERATOR_ERR"))
+
+	_, err := suite.branchList.ListBranches()
+
+	suite.NotNil(err)
+}
+
+func (suite *BranchListTestSuite) TestListBranches_WhenBranchIteratorReturnsError_ShouldReturnError() {
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().Name().Return("refs/head/master")
+	suite.mockRepo.EXPECT().NewBranchIterator(git2go.BranchAll).Return(suite.mockIterator, nil)
+	suite.mockIterator.EXPECT().ForEach(gomock.Any()).Return(errors.New("iterator error"))
+
+	_, err := suite.branchList.ListBranches()
 
 	suite.NotNil(err)
-	suite.Empty(branchList)
 }
diff --git a/git/middleware/branch.go b/git/middleware/branch.go
index a0b6ad1..bf50278 100644
--- a/git/middleware/branch.go
+++ b/git/middleware/branch.go
@@ -7,12 +7,32 @@ type Branch interface {
 	Delete() error
 	Cmp(r Reference) int
 	Reference() Reference
+	IsRemote() bool
+	Name() (string, error)
+	IsTag() bool
+	IsNote() bool
 }
 
 type branch struct {
 	branch *git2go.Branch
 }
 
+func (b branch) IsNote() bool {
+	return b.branch.IsNote()
+}
+
+func (b branch) IsTag() bool {
+	return b.branch.IsTag()
+}
+
+func (b branch) Name() (string, error) {
+	return b.branch.Name()
+}
+
+func (b branch) IsRemote() bool {
+	return b.branch.IsRemote()
+}
+
 func (b branch) Reference() Reference {
 	return NewReference(b.branch.Reference)
 }
diff --git a/git/middleware/branch_iterator.go b/git/middleware/branch_iterator.go
new file mode 100644
index 0000000..7ec4c33
--- /dev/null
+++ b/git/middleware/branch_iterator.go
@@ -0,0 +1,19 @@
+package middleware
+
+import git "github.com/libgit2/git2go/v31"
+
+type BranchIterator interface {
+	ForEach(func(b *git.Branch, branchType git.BranchType) error) error
+}
+
+type branchIterator struct {
+	iterator *git.BranchIterator
+}
+
+func (b branchIterator) ForEach(f func(b *git.Branch, branchType git.BranchType) error) error {
+	return b.iterator.ForEach(f)
+}
+
+func NewBranchIterator(iterator *git.BranchIterator) BranchIterator {
+	return branchIterator{iterator: iterator}
+}
diff --git a/git/middleware/repository.go b/git/middleware/repository.go
index 7399138..b9f072d 100644
--- a/git/middleware/repository.go
+++ b/git/middleware/repository.go
@@ -18,15 +18,20 @@ type Repository interface {
 	CheckoutTree(tree *git.Tree, c *git.CheckoutOptions) error
 	SetHead(name string) error
 	GetGitRepository() *git.Repository
-	NewBranchIterator(branchType git.BranchType) (*git.BranchIterator, error)
+	NewBranchIterator(branchType git.BranchType) (BranchIterator, error)
 }
 
 type repository struct {
 	repo *git.Repository
 }
 
-func (r repository) NewBranchIterator(branchType git.BranchType) (*git.BranchIterator, error) {
-	return r.repo.NewBranchIterator(branchType)
+func (r repository) NewBranchIterator(branchType git.BranchType) (BranchIterator, error) {
+	itr, err := r.repo.NewBranchIterator(branchType)
+	if err != nil {
+		return nil, err
+	}
+
+	return NewBranchIterator(itr), nil
 }
 
 func (r repository) SetHead(name string) error {
diff --git a/mocks/mock_branch.go b/mocks/mock_branch.go
index ff0a721..baa1728 100644
--- a/mocks/mock_branch.go
+++ b/mocks/mock_branch.go
@@ -63,6 +63,63 @@ func (mr *MockBranchMockRecorder) Delete() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockBranch)(nil).Delete))
 }
 
+// IsNote mocks base method.
+func (m *MockBranch) IsNote() bool {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "IsNote")
+	ret0, _ := ret[0].(bool)
+	return ret0
+}
+
+// IsNote indicates an expected call of IsNote.
+func (mr *MockBranchMockRecorder) IsNote() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsNote", reflect.TypeOf((*MockBranch)(nil).IsNote))
+}
+
+// IsRemote mocks base method.
+func (m *MockBranch) IsRemote() bool {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "IsRemote")
+	ret0, _ := ret[0].(bool)
+	return ret0
+}
+
+// IsRemote indicates an expected call of IsRemote.
+func (mr *MockBranchMockRecorder) IsRemote() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsRemote", reflect.TypeOf((*MockBranch)(nil).IsRemote))
+}
+
+// IsTag mocks base method.
+func (m *MockBranch) IsTag() bool {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "IsTag")
+	ret0, _ := ret[0].(bool)
+	return ret0
+}
+
+// IsTag indicates an expected call of IsTag.
+func (mr *MockBranchMockRecorder) IsTag() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsTag", reflect.TypeOf((*MockBranch)(nil).IsTag))
+}
+
+// Name mocks base method.
+func (m *MockBranch) Name() (string, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Name")
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Name indicates an expected call of Name.
+func (mr *MockBranchMockRecorder) Name() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockBranch)(nil).Name))
+}
+
 // Reference mocks base method.
 func (m *MockBranch) Reference() middleware.Reference {
 	m.ctrl.T.Helper()
diff --git a/mocks/mock_branch_iterator.go b/mocks/mock_branch_iterator.go
new file mode 100644
index 0000000..db3ba41
--- /dev/null
+++ b/mocks/mock_branch_iterator.go
@@ -0,0 +1,49 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/branch_iterator.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockBranchIterator is a mock of BranchIterator interface.
+type MockBranchIterator struct {
+	ctrl     *gomock.Controller
+	recorder *MockBranchIteratorMockRecorder
+}
+
+// MockBranchIteratorMockRecorder is the mock recorder for MockBranchIterator.
+type MockBranchIteratorMockRecorder struct {
+	mock *MockBranchIterator
+}
+
+// NewMockBranchIterator creates a new mock instance.
+func NewMockBranchIterator(ctrl *gomock.Controller) *MockBranchIterator {
+	mock := &MockBranchIterator{ctrl: ctrl}
+	mock.recorder = &MockBranchIteratorMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockBranchIterator) EXPECT() *MockBranchIteratorMockRecorder {
+	return m.recorder
+}
+
+// ForEach mocks base method.
+func (m *MockBranchIterator) ForEach(arg0 func(*git.Branch, git.BranchType) error) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ForEach", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// ForEach indicates an expected call of ForEach.
+func (mr *MockBranchIteratorMockRecorder) ForEach(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForEach", reflect.TypeOf((*MockBranchIterator)(nil).ForEach), arg0)
+}
diff --git a/mocks/mock_reference.go b/mocks/mock_reference.go
index 8dd9b55..914d7a7 100644
--- a/mocks/mock_reference.go
+++ b/mocks/mock_reference.go
@@ -48,6 +48,20 @@ func (mr *MockReferenceMockRecorder) GetGitReference() *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGitReference", reflect.TypeOf((*MockReference)(nil).GetGitReference))
 }
 
+// Name mocks base method.
+func (m *MockReference) Name() string {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Name")
+	ret0, _ := ret[0].(string)
+	return ret0
+}
+
+// Name indicates an expected call of Name.
+func (mr *MockReferenceMockRecorder) Name() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockReference)(nil).Name))
+}
+
 // SetTarget mocks base method.
 func (m *MockReference) SetTarget(id *git.Oid, message string) (*git.Reference, error) {
 	m.ctrl.T.Helper()
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
index bb6499b..2cfbb92 100644
--- a/mocks/mock_repository.go
+++ b/mocks/mock_repository.go
@@ -218,6 +218,21 @@ func (mr *MockRepositoryMockRecorder) LookupTree(id interface{}) *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupTree", reflect.TypeOf((*MockRepository)(nil).LookupTree), id)
 }
 
+// NewBranchIterator mocks base method.
+func (m *MockRepository) NewBranchIterator(branchType git.BranchType) (middleware.BranchIterator, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewBranchIterator", branchType)
+	ret0, _ := ret[0].(middleware.BranchIterator)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// NewBranchIterator indicates an expected call of NewBranchIterator.
+func (mr *MockRepositoryMockRecorder) NewBranchIterator(branchType interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewBranchIterator", reflect.TypeOf((*MockRepository)(nil).NewBranchIterator), branchType)
+}
+
 // Remotes mocks base method.
 func (m *MockRepository) Remotes() middleware.Remotes {
 	m.ctrl.T.Helper()

From 75bc2fb407359cd7241d7043119a16b1fd2c160c Mon Sep 17 00:00:00 2001
From: Neel <47709856+neel1996@users.noreply.github.com>
Date: Sun, 19 Sep 2021 20:49:20 +0530
Subject: [PATCH 132/148] replace containerized test with make script

---
 .github/workflows/go-collab.yml | 7 +++++--
 .github/workflows/go.yml        | 7 +++++--
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index bec6870..3d089bc 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -37,14 +37,17 @@ jobs:
       - name: Check out code into the Go module directory
         uses: actions/checkout@v2
 
-      - name: Run Go Test
+      - name: Setup Test Artifacts
         run: |
           sudo cp /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/lib* /usr/lib
           export PATH="/home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/:$PATH"
           git config --global user.name "${{ secrets.ACTION_USER_NAME }}" && git config --global user.email "${{ secrets.ACTION_USER_EMAIL }}"
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
-          make dockerise-test
+
+      - name: Run Go Test
+        shell: bash
+        run: make test-ci
 
   gitconvex-build:
     needs:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 3bef90f..13a333b 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -37,14 +37,17 @@ jobs:
       - name: Check out code into the Go module directory
         uses: actions/checkout@v2
 
-      - name: Run Go Test
+      - name: Setup Test Artifacts
         run: |
           sudo cp /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/lib* /usr/lib
           export PATH="/home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/:$PATH"
           git config --global user.name "${{ secrets.ACTION_USER_NAME }}" && git config --global user.email "${{ secrets.ACTION_USER_EMAIL }}"
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
-          make dockerise-test
+
+      - name: Run Go Test
+        shell: bash
+        run: make test-ci
 
   gitconvex-build:
     needs:

From 47078e4acd908b71c4869a8f3b7a6f07548c5331 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 20 Sep 2021 21:51:31 +0530
Subject: [PATCH 133/148] add logger to failing test

---
 .github/workflows/go.yml           | 6 ++++++
 git/branch/git_branch_list_test.go | 3 +++
 2 files changed, 9 insertions(+)

diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 13a333b..2898a08 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -45,6 +45,12 @@ jobs:
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
 
+      - name: Try GOtestsum
+        run: |
+          go get gotest.tools/gotestsum
+          export PATH=$PATH:$(go env GOPATH)/bin
+          gotestsum ./... -cover
+
       - name: Run Go Test
         shell: bash
         run: make test-ci
diff --git a/git/branch/git_branch_list_test.go b/git/branch/git_branch_list_test.go
index e42dc33..c8f5251 100644
--- a/git/branch/git_branch_list_test.go
+++ b/git/branch/git_branch_list_test.go
@@ -8,6 +8,7 @@ import (
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
+	"log"
 	"os"
 	"testing"
 )
@@ -47,6 +48,8 @@ func (suite *BranchListTestSuite) TestListBranches_WhenRepoHasBranches_ShouldRet
 
 	branchList, err := suite.branchList.ListBranches()
 
+	log.Println(branchList)
+
 	suite.Nil(err)
 	suite.Equal(2, len(branchList.BranchList))
 	suite.Equal(3, len(branchList.AllBranchList))

From e599ca01a5d226774a6f8d3adb3ebaa77312126f Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 20 Sep 2021 22:34:46 +0530
Subject: [PATCH 134/148] revise unit tests for better functionality coverage

---
 git/branch/checkout/checkout_local_branch_test.go  |  2 +-
 git/branch/checkout/checkout_remote_branch_test.go | 10 +++++-----
 git/branch/git_branch_compare.go                   |  2 --
 3 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/git/branch/checkout/checkout_local_branch_test.go b/git/branch/checkout/checkout_local_branch_test.go
index 70b8e77..8ab094c 100644
--- a/git/branch/checkout/checkout_local_branch_test.go
+++ b/git/branch/checkout/checkout_local_branch_test.go
@@ -43,7 +43,7 @@ func (suite *CheckOutLocalBranchTestSuite) SetupSuite() {
 }
 
 func (suite *CheckOutLocalBranchTestSuite) TearDownSuite() {
-	branch.NewDeleteBranch(suite.repo, validator.NewBranchValidator())
+	_ = branch.NewDeleteBranch(suite.repo, validator.NewBranchValidator()).DeleteBranch(suite.branchName)
 }
 
 func (suite *CheckOutLocalBranchTestSuite) SetupTest() {
diff --git a/git/branch/checkout/checkout_remote_branch_test.go b/git/branch/checkout/checkout_remote_branch_test.go
index 8c29ec6..735d0e4 100644
--- a/git/branch/checkout/checkout_remote_branch_test.go
+++ b/git/branch/checkout/checkout_remote_branch_test.go
@@ -44,10 +44,10 @@ func (suite *CheckOutRemoteBranchTestSuite) SetupSuite() {
 	}
 
 	suite.repo = middleware.NewRepository(r)
-	suite.branchName = "remotes/origin/master"
-	suite.remoteBranchName = "origin/master"
-	suite.localBranchName = "master"
-	suite.localBranchReferenceName = "refs/heads/master"
+	suite.branchName = "remotes/origin/test_remote"
+	suite.remoteBranchName = "origin/test_remote"
+	suite.localBranchName = "test_remote"
+	suite.localBranchReferenceName = "refs/heads/test_remote"
 }
 
 func (suite *CheckOutRemoteBranchTestSuite) SetupTest() {
@@ -68,7 +68,7 @@ func (suite *CheckOutRemoteBranchTestSuite) TearDownTest() {
 }
 
 func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenBranchIsValid_ShouldCheckoutLocalBranch() {
-	suite.checkOutRemoteBranch = NewCheckoutRemoteBranch(suite.repo, suite.branchName, nil)
+	suite.checkOutRemoteBranch = NewCheckoutRemoteBranch(suite.repo, suite.branchName, branch.NewAddBranch(suite.repo, validator.NewBranchValidator()))
 
 	err := suite.checkOutRemoteBranch.CheckoutBranch()
 
diff --git a/git/branch/git_branch_compare.go b/git/branch/git_branch_compare.go
index b4041d7..22aa55e 100644
--- a/git/branch/git_branch_compare.go
+++ b/git/branch/git_branch_compare.go
@@ -1,7 +1,6 @@
 package branch
 
 import (
-	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/global"
@@ -187,7 +186,6 @@ func getParentCommitsOf(head middleware.Commit) map[string]middleware.Commit {
 
 	next = head.Parent(0)
 	for next != nil {
-		fmt.Println("Next : ", next)
 		commitMap[next.Id().String()] = next
 		next = next.Parent(0)
 	}

From 53b79b385e551632187721f8c19c4b9f18650794 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 20 Sep 2021 22:42:30 +0530
Subject: [PATCH 135/148] fix unit test for branch list api and update make
 targets for running tests

---
 Makefile                                      |  4 ++--
 git/branch/git_branch_list_test.go            | 11 ++++++++--
 git/branch/test_utils/checkout_branch_util.go | 20 +++++++++++++++++++
 3 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/Makefile b/Makefile
index 8e8c807..8b38dff 100644
--- a/Makefile
+++ b/Makefile
@@ -49,14 +49,14 @@ test-pretty:
  	go clean --cache && \
  	./build_scripts/remove_test_repo.sh && \
  	./build_scripts/clone_test_repo.sh && \
- 	gotestsum ./... -count=1 -cover -coverprofile=coverage.out && \
+ 	gotestsum ./... -count=1 -p=1 -cover -coverprofile=coverage.out && \
 	rm -rf $$GITCONVEX_TEST_REPO
 
 test-ci: git-testuser-setup
 	go generate && \
 	go clean --cache && \
     sh ./build_scripts/clone_test_repo.sh && \
-    go test ./... -count=1 -cover -coverprofile=coverage.out && \
+    go test ./... -count=1 -p=1 -cover -coverprofile=coverage.out && \
     rm -rf $$GITCONVEX_TEST_REPO
 
 dockerise-test:
diff --git a/git/branch/git_branch_list_test.go b/git/branch/git_branch_list_test.go
index c8f5251..9d836f9 100644
--- a/git/branch/git_branch_list_test.go
+++ b/git/branch/git_branch_list_test.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"github.com/golang/mock/gomock"
 	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/branch/test_utils"
 	"github.com/neel1996/gitconvex/git/middleware"
 	"github.com/neel1996/gitconvex/mocks"
 	"github.com/stretchr/testify/suite"
@@ -28,14 +29,20 @@ func TestBranchListTestSuite(t *testing.T) {
 	suite.Run(t, new(BranchListTestSuite))
 }
 
-func (suite *BranchListTestSuite) SetupTest() {
+func (suite *BranchListTestSuite) SetupSuite() {
 	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	if err != nil {
 		fmt.Println(err)
 	}
 
-	suite.mockController = gomock.NewController(suite.T())
 	suite.repo = middleware.NewRepository(r)
+
+	test_utils.CheckoutTestBranchWithType(suite.repo, "test_remote", git2go.BranchRemote)
+	test_utils.CheckoutTestBranch(suite.repo, "master")
+}
+
+func (suite *BranchListTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
 	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
 	suite.mockReference = mocks.NewMockReference(suite.mockController)
 	suite.mockIterator = mocks.NewMockBranchIterator(suite.mockController)
diff --git a/git/branch/test_utils/checkout_branch_util.go b/git/branch/test_utils/checkout_branch_util.go
index 53c9d1f..be04ef7 100644
--- a/git/branch/test_utils/checkout_branch_util.go
+++ b/git/branch/test_utils/checkout_branch_util.go
@@ -16,3 +16,23 @@ func CheckoutTestBranch(repo middleware.Repository, branchName string) {
 	})
 	fmt.Println(repo.SetHead("refs/heads/" + branchName))
 }
+
+func CheckoutTestBranchWithType(repo middleware.Repository, branchName string, branchType git2go.BranchType) {
+	defer func() {
+		if r := recover(); r != nil {
+			fmt.Println(r)
+		}
+	}()
+
+	branch, err := repo.LookupBranch(branchName, branchType)
+	if err != nil {
+		AddTestBranch(repo, branchName)
+	}
+	targetCommit, _ := repo.LookupCommitV2(branch.Target())
+	tree, _ := targetCommit.Tree()
+	_ = repo.CheckoutTree(tree, &git2go.CheckoutOptions{
+		Strategy:       git2go.CheckoutSafe,
+		DisableFilters: false,
+	})
+	fmt.Println(repo.SetHead("refs/heads/" + branchName))
+}

From f976a5a39e009eba3b2668ae3099d66dc1d2979b Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 20 Sep 2021 23:11:47 +0530
Subject: [PATCH 136/148] add new make target to run gotestsum in the pipeline

---
 .github/workflows/go.yml | 3 +--
 Makefile                 | 8 ++++++++
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 2898a08..1746ca1 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -47,9 +47,8 @@ jobs:
 
       - name: Try GOtestsum
         run: |
-          go get gotest.tools/gotestsum
           export PATH=$PATH:$(go env GOPATH)/bin
-          gotestsum ./... -cover
+          make test-ci-pretty
 
       - name: Run Go Test
         shell: bash
diff --git a/Makefile b/Makefile
index 8b38dff..189a378 100644
--- a/Makefile
+++ b/Makefile
@@ -59,6 +59,14 @@ test-ci: git-testuser-setup
     go test ./... -count=1 -p=1 -cover -coverprofile=coverage.out && \
     rm -rf $$GITCONVEX_TEST_REPO
 
+test-ci-pretty: git-testuser-setup
+	go generate && \
+	go clean --cache && \
+    sh ./build_scripts/clone_test_repo.sh && \
+    go get gotest.tools/gotestsum && \
+    gotestsum ./... -count=1 -p=1 -cover -coverprofile=coverage.out && \
+    rm -rf $$GITCONVEX_TEST_REPO
+
 dockerise-test:
 	rm -rf $$GITCONVEX_TEST_REPO && \
 	docker-compose -f docker-compose.test.yaml build && \

From 2d2b2945443da6f51b331544a54cb28492ee858f Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 20 Sep 2021 23:16:41 +0530
Subject: [PATCH 137/148] update go test stage in actions yaml

---
 .github/workflows/go-collab.yml | 4 +++-
 .github/workflows/go.yml        | 7 ++-----
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index 3d089bc..9851be5 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -47,7 +47,9 @@ jobs:
 
       - name: Run Go Test
         shell: bash
-        run: make test-ci
+        run: |
+          export PATH=$PATH:$(go env GOPATH)/bin
+          make test-ci-pretty
 
   gitconvex-build:
     needs:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 1746ca1..9516680 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -45,15 +45,12 @@ jobs:
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
 
-      - name: Try GOtestsum
+      - name: Run Go Test
+        shell: bash
         run: |
           export PATH=$PATH:$(go env GOPATH)/bin
           make test-ci-pretty
 
-      - name: Run Go Test
-        shell: bash
-        run: make test-ci
-
   gitconvex-build:
     needs:
       - gitconvex-test

From 9b786e68d801a467b42f70db1e35f97921a4ec16 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Mon, 20 Sep 2021 23:25:43 +0530
Subject: [PATCH 138/148] improve test coverage for validators

---
 validator/branch_validator_test.go  |  9 ++++++++-
 validator/repo_validator_test.go    |  9 +++++++++
 validator/validation_errors_test.go | 21 +++++++++++++++++++++
 3 files changed, 38 insertions(+), 1 deletion(-)
 create mode 100644 validator/validation_errors_test.go

diff --git a/validator/branch_validator_test.go b/validator/branch_validator_test.go
index bc3fef7..cfe2be2 100644
--- a/validator/branch_validator_test.go
+++ b/validator/branch_validator_test.go
@@ -30,9 +30,16 @@ func (suite *BranchValidatorTestSuite) TestValidate_WhenPassedBranchesAreValid_S
 	suite.Nil(err)
 }
 
-func (suite *BranchValidatorTestSuite) TestValidate_WhenPassedEmptyStringIsPassed_ShouldReturnEmptybranchError() {
+func (suite *BranchValidatorTestSuite) TestValidate_WhenNoBranchesArePassed_ShouldReturnEmptyBranchError() {
 	err := suite.branchValidator.ValidateWithFields()
 
 	suite.NotNil(err)
 	suite.Equal(EmptyBranchName, err)
 }
+
+func (suite *BranchValidatorTestSuite) TestValidate_WhenEmptyStringIsPassed_ShouldReturnEmptyBranchError() {
+	err := suite.branchValidator.ValidateWithFields("")
+
+	suite.NotNil(err)
+	suite.Equal(EmptyBranchName, err)
+}
diff --git a/validator/repo_validator_test.go b/validator/repo_validator_test.go
index 5ee9df7..094e02a 100644
--- a/validator/repo_validator_test.go
+++ b/validator/repo_validator_test.go
@@ -42,3 +42,12 @@ func (suite *RepoValidatorTestSuite) TestValidate_WhenRepoIsNil_ShouldReturnRepo
 	suite.NotNil(err)
 	suite.Equal(NilRepoError, err)
 }
+
+func (suite *RepoValidatorTestSuite) TestValidate_WhenWrongTypeOfInputIsPassed_ShouldReturnRepoNilError() {
+	suite.repoValidator = NewRepoValidator()
+
+	err := suite.repoValidator.Validate("nil")
+
+	suite.NotNil(err)
+	suite.Equal(NilRepoError, err)
+}
diff --git a/validator/validation_errors_test.go b/validator/validation_errors_test.go
new file mode 100644
index 0000000..096e04f
--- /dev/null
+++ b/validator/validation_errors_test.go
@@ -0,0 +1,21 @@
+package validator
+
+import (
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type ValidationErrorTestSuite struct {
+	suite.Suite
+	validationError Error
+}
+
+func TestValidationErrorTestSuite(t *testing.T) {
+	suite.Run(t, new(ValidationErrorTestSuite))
+}
+
+func (suite *ValidationErrorTestSuite) TestError_ShouldReturnErrorString() {
+	suite.validationError = NilRepoError
+
+	suite.Equal("Repo is nil", suite.validationError.Error())
+}

From b5d9e797ad4cce116ee42d0e768eb01d2281feae Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 21 Sep 2021 22:57:58 +0530
Subject: [PATCH 139/148] update branch compare test assertion

---
 git/branch/git_branch_compare_test.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
index 36bc965..72c0b26 100644
--- a/git/branch/git_branch_compare_test.go
+++ b/git/branch/git_branch_compare_test.go
@@ -91,7 +91,7 @@ func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchesHaveDifferent
 	suite.NotNil(*compareResults[0].Commits[0])
 	suite.NotEmpty(*compareResults[0].Commits[0].CommitMessage)
 	suite.NotEmpty(compareResults[0].Date)
-	suite.Equal(2, len(compareResults[0].Commits))
+	suite.GreaterOrEqual(1, len(compareResults[0].Commits))
 }
 
 func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchValidationFails_ShouldReturnError() {

From c994a8e10b032da8628539ff885ea06b8f443aa3 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Tue, 21 Sep 2021 22:59:31 +0530
Subject: [PATCH 140/148] fix test assertion for branch compare api

---
 git/branch/git_branch_compare_test.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
index 72c0b26..c9c7235 100644
--- a/git/branch/git_branch_compare_test.go
+++ b/git/branch/git_branch_compare_test.go
@@ -91,7 +91,7 @@ func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchesHaveDifferent
 	suite.NotNil(*compareResults[0].Commits[0])
 	suite.NotEmpty(*compareResults[0].Commits[0].CommitMessage)
 	suite.NotEmpty(compareResults[0].Date)
-	suite.GreaterOrEqual(1, len(compareResults[0].Commits))
+	suite.GreaterOrEqual(len(compareResults[0].Commits), 1)
 }
 
 func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchValidationFails_ShouldReturnError() {

From 7f080709ed7b96a990c2dc2fea455e8fb36cc77f Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 22 Sep 2021 22:15:21 +0530
Subject: [PATCH 141/148] add actions stage to check test coverage level

---
 .github/workflows/go.yml        | 9 +++++++++
 Makefile                        | 3 +++
 build_scripts/check_coverage.sh | 8 ++++++++
 3 files changed, 20 insertions(+)
 create mode 100644 build_scripts/check_coverage.sh

diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 9516680..c9f5807 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -21,6 +21,7 @@ jobs:
       PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
       GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/gitconvex-test
       GITCONVEX_DEFAULT_PATH: /usr/local/gitconvex
+      COVERAGE_THRESHOLD: 90
 
     steps:
       - name: Install libgit2 from Homebrew
@@ -51,6 +52,14 @@ jobs:
           export PATH=$PATH:$(go env GOPATH)/bin
           make test-ci-pretty
 
+      - name: Check Coverage
+        shell: bash
+        run: |
+          export COVERAGE_PERCENT=`go tool cover -func=coverage.out | grep "total:" | grep -Eo '[0-9]+\.[0-9]+'`
+          echo "Current coverage percentage : $COVERAGE_PERCENT"
+          make check-coverage
+
+
   gitconvex-build:
     needs:
       - gitconvex-test
diff --git a/Makefile b/Makefile
index 189a378..70558c6 100644
--- a/Makefile
+++ b/Makefile
@@ -72,6 +72,9 @@ dockerise-test:
 	docker-compose -f docker-compose.test.yaml build && \
 	docker-compose -f docker-compose.test.yaml up
 
+check-coverage:
+	sh ./build_scripts/check_coverage.sh
+
 show-coverage:
 	go tool cover -html=coverage.out
 
diff --git a/build_scripts/check_coverage.sh b/build_scripts/check_coverage.sh
new file mode 100644
index 0000000..9b277e9
--- /dev/null
+++ b/build_scripts/check_coverage.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+if [[ $COVERAGE_PERCENT < $COVERAGE_THRESHOLD ]];
+then
+  echo "Coverage $COVERAGE_PERCENT is less that the threshold $COVERAGE_THRESHOLD" && exit 1;
+else
+  echo " ✔️ Good work! Coverage $COVERAGE_PERCENT meets the expectation"
+fi;
\ No newline at end of file

From 30b1d14fdf1b7122d94e8b6aa7cb1c7f40218016 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 22 Sep 2021 22:25:02 +0530
Subject: [PATCH 142/148] remove sh from check-coverage target to avoid shell
 conflict

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 70558c6..53ecef9 100644
--- a/Makefile
+++ b/Makefile
@@ -73,7 +73,7 @@ dockerise-test:
 	docker-compose -f docker-compose.test.yaml up
 
 check-coverage:
-	sh ./build_scripts/check_coverage.sh
+	./build_scripts/check_coverage.sh
 
 show-coverage:
 	go tool cover -html=coverage.out

From 06374deb201634649b61f4b5e024310fc5da602e Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Wed, 22 Sep 2021 22:53:39 +0530
Subject: [PATCH 143/148] update makefile to run check-coverage with bash

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 53ecef9..fadd138 100644
--- a/Makefile
+++ b/Makefile
@@ -73,7 +73,7 @@ dockerise-test:
 	docker-compose -f docker-compose.test.yaml up
 
 check-coverage:
-	./build_scripts/check_coverage.sh
+	bash ./build_scripts/check_coverage.sh
 
 show-coverage:
 	go tool cover -html=coverage.out

From 13b939e6cf87926ec0ce9b8c4c7a898b7c41a094 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Thu, 23 Sep 2021 23:58:58 +0530
Subject: [PATCH 144/148] add unit test for commit search factory

---
 git/commit/search/search_factory_test.go | 39 ++++++++++++++++++++++++
 1 file changed, 39 insertions(+)
 create mode 100644 git/commit/search/search_factory_test.go

diff --git a/git/commit/search/search_factory_test.go b/git/commit/search/search_factory_test.go
new file mode 100644
index 0000000..21ecd8f
--- /dev/null
+++ b/git/commit/search/search_factory_test.go
@@ -0,0 +1,39 @@
+package search
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type SearchFactoryTestSuite struct {
+	suite.Suite
+}
+
+func TestSearchFactoryTestSuite(t *testing.T) {
+	suite.Run(t, new(SearchFactoryTestSuite))
+}
+
+func (suite *SearchFactoryTestSuite) TestGetSearchAction_ShouldReturnCommitHashSearchAction() {
+	action := GetSearchAction("hash", []git2go.Commit{})
+
+	suite.IsType(commitHashSearch{}, action)
+}
+
+func (suite *SearchFactoryTestSuite) TestGetSearchAction_ShouldReturnCommitAuthorSearchAction() {
+	action := GetSearchAction("author", []git2go.Commit{})
+
+	suite.IsType(commitAuthorSearch{}, action)
+}
+
+func (suite *SearchFactoryTestSuite) TestGetSearchAction_ShouldReturnCommitMessageSearchAction() {
+	action := GetSearchAction("message", []git2go.Commit{})
+
+	suite.IsType(commitMessageSearch{}, action)
+}
+
+func (suite *SearchFactoryTestSuite) TestGetSearchAction_WhenTypeIsInvalid_ShouldReturnNil() {
+	action := GetSearchAction("invalid", []git2go.Commit{})
+
+	suite.Nil(action)
+}

From 691c9a917cec687ce29a5ed71d8edc4205346a2a Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 26 Sep 2021 22:37:59 +0530
Subject: [PATCH 145/148] add unit test suite for author based search

---
 .../search/commit_author_search_test.go       | 37 +++++++++++++++++++
 .../search/test_utils/commit_log_util.go      | 25 +++++++++++++
 2 files changed, 62 insertions(+)
 create mode 100644 git/commit/search/commit_author_search_test.go
 create mode 100644 git/commit/search/test_utils/commit_log_util.go

diff --git a/git/commit/search/commit_author_search_test.go b/git/commit/search/commit_author_search_test.go
new file mode 100644
index 0000000..a6967b0
--- /dev/null
+++ b/git/commit/search/commit_author_search_test.go
@@ -0,0 +1,37 @@
+package search
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/commit/search/test_utils"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type CommitAuthorSearchTestSuite struct {
+	suite.Suite
+	search     Search
+	allCommits []git2go.Commit
+}
+
+func TestCommitAuthorSearchTestSuite(t *testing.T) {
+	suite.Run(t, new(CommitAuthorSearchTestSuite))
+}
+
+func (suite *CommitAuthorSearchTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	repo := middleware.NewRepository(r)
+	suite.allCommits = test_utils.GetAllTestCommitLogs(repo)
+	suite.search = GetSearchAction("author", suite.allCommits)
+}
+
+func (suite *CommitAuthorSearchTestSuite) TestSearch_WhenCommitHasMatchingAuthor_ShouldReturnCommits() {
+	commits := suite.search.Search("test")
+
+	suite.NotZero(len(commits))
+}
diff --git a/git/commit/search/test_utils/commit_log_util.go b/git/commit/search/test_utils/commit_log_util.go
new file mode 100644
index 0000000..a6c9fbf
--- /dev/null
+++ b/git/commit/search/test_utils/commit_log_util.go
@@ -0,0 +1,25 @@
+package test_utils
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+func GetAllTestCommitLogs(repo middleware.Repository) []git2go.Commit {
+	var commits []git2go.Commit
+
+	logItr, _ := repo.Walk()
+
+	err := logItr.PushHead()
+	err = logItr.Iterate(func(commit *git2go.Commit) bool {
+		if commit != nil {
+			commits = append(commits, *commit)
+			return true
+		}
+		return false
+	})
+
+	fmt.Println(err)
+	return commits
+}

From ee511648cf14340859dbea766013287688c6f232 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 26 Sep 2021 22:59:58 +0530
Subject: [PATCH 146/148] add unit test suite for commit hash based search

---
 git/commit/search/commit_hash_search_test.go | 37 ++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 git/commit/search/commit_hash_search_test.go

diff --git a/git/commit/search/commit_hash_search_test.go b/git/commit/search/commit_hash_search_test.go
new file mode 100644
index 0000000..37fa2f0
--- /dev/null
+++ b/git/commit/search/commit_hash_search_test.go
@@ -0,0 +1,37 @@
+package search
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/commit/search/test_utils"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type CommitHashSearchTestSuite struct {
+	suite.Suite
+	search     Search
+	allCommits []git2go.Commit
+}
+
+func TestCommitHashSearchTestSuite(t *testing.T) {
+	suite.Run(t, new(CommitHashSearchTestSuite))
+}
+
+func (suite *CommitHashSearchTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	repo := middleware.NewRepository(r)
+	suite.allCommits = test_utils.GetAllTestCommitLogs(repo)
+	suite.search = GetSearchAction("hash", suite.allCommits)
+}
+
+func (suite *CommitHashSearchTestSuite) TestSearch_ShouldReturnCommitsMatchingHash() {
+	commits := suite.search.Search("0")
+
+	suite.NotZero(len(commits))
+}

From 62151087d71b9a3deb7a3ae5495097c5fff0c2f0 Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 26 Sep 2021 23:00:21 +0530
Subject: [PATCH 147/148] remove methods from commit search interface

---
 git/commit/search/commit_author_search.go  | 8 ++------
 git/commit/search/commit_hash_search.go    | 8 --------
 git/commit/search/commit_message_search.go | 4 ++--
 git/commit/search/search.go                | 2 --
 4 files changed, 4 insertions(+), 18 deletions(-)

diff --git a/git/commit/search/commit_author_search.go b/git/commit/search/commit_author_search.go
index fa01726..45ad4cf 100644
--- a/git/commit/search/commit_author_search.go
+++ b/git/commit/search/commit_author_search.go
@@ -11,10 +11,6 @@ type commitAuthorSearch struct {
 	commits []git.Commit
 }
 
-func (h commitAuthorSearch) New(commits []git.Commit) Search {
-	return commitAuthorSearch{commits: commits}
-}
-
 func (h commitAuthorSearch) Search(searchKey string) []git.Commit {
 	var (
 		matchingCommits []git.Commit
@@ -26,7 +22,7 @@ func (h commitAuthorSearch) Search(searchKey string) []git.Commit {
 			break
 		}
 
-		if isMatch, _ := regexp.MatchString(h.ToLower(searchKey), h.ToLower(commit.Author().Name)); isMatch {
+		if isMatch, _ := regexp.MatchString(h.toLower(searchKey), h.toLower(commit.Author().Name)); isMatch {
 			matchingCommits = append(matchingCommits, commit)
 			counter++
 		}
@@ -35,7 +31,7 @@ func (h commitAuthorSearch) Search(searchKey string) []git.Commit {
 	return matchingCommits
 }
 
-func (h commitAuthorSearch) ToLower(value string) string {
+func (h commitAuthorSearch) toLower(value string) string {
 	return strings.ToLower(strings.TrimSpace(value))
 }
 
diff --git a/git/commit/search/commit_hash_search.go b/git/commit/search/commit_hash_search.go
index e58d4ff..ed95335 100644
--- a/git/commit/search/commit_hash_search.go
+++ b/git/commit/search/commit_hash_search.go
@@ -10,10 +10,6 @@ type commitHashSearch struct {
 	commits []git.Commit
 }
 
-func (h commitHashSearch) New(commits []git.Commit) Search {
-	return commitHashSearch{commits: commits}
-}
-
 func (h commitHashSearch) Search(searchKey string) []git.Commit {
 	var (
 		matchingCommits []git.Commit
@@ -34,10 +30,6 @@ func (h commitHashSearch) Search(searchKey string) []git.Commit {
 	return matchingCommits
 }
 
-func (h commitHashSearch) ToLower(_ string) string {
-	panic("Not applicable for hash search")
-}
-
 func (h commitHashSearch) isExceedingSearchLimit(searchLimitCounter int) bool {
 	return searchLimitCounter == constants.SearchLimit
 }
diff --git a/git/commit/search/commit_message_search.go b/git/commit/search/commit_message_search.go
index 51fa06d..5598e94 100644
--- a/git/commit/search/commit_message_search.go
+++ b/git/commit/search/commit_message_search.go
@@ -26,7 +26,7 @@ func (m commitMessageSearch) Search(searchKey string) []git.Commit {
 			break
 		}
 
-		if isMatch, _ := regexp.MatchString(m.ToLower(searchKey), m.ToLower(commit.Message())); isMatch {
+		if isMatch, _ := regexp.MatchString(m.toLower(searchKey), m.toLower(commit.Message())); isMatch {
 			matchingCommits = append(matchingCommits, commit)
 			counter++
 		}
@@ -35,7 +35,7 @@ func (m commitMessageSearch) Search(searchKey string) []git.Commit {
 	return matchingCommits
 }
 
-func (m commitMessageSearch) ToLower(value string) string {
+func (m commitMessageSearch) toLower(value string) string {
 	return strings.ToLower(strings.TrimSpace(value))
 }
 
diff --git a/git/commit/search/search.go b/git/commit/search/search.go
index 558813e..549600b 100644
--- a/git/commit/search/search.go
+++ b/git/commit/search/search.go
@@ -6,6 +6,4 @@ import (
 
 type Search interface {
 	Search(string) []git2go.Commit
-	New([]git2go.Commit) Search
-	ToLower(string) string
 }

From 246b6505f568a94a8e3695c9fa45712538d8c6be Mon Sep 17 00:00:00 2001
From: neel1996 <neelusenthil1996@gmail.com>
Date: Sun, 26 Sep 2021 23:05:26 +0530
Subject: [PATCH 148/148] add test suite for commit message based search api

---
 git/commit/search/commit_message_search.go    |  4 --
 .../search/commit_message_search_test.go      | 37 +++++++++++++++++++
 2 files changed, 37 insertions(+), 4 deletions(-)
 create mode 100644 git/commit/search/commit_message_search_test.go

diff --git a/git/commit/search/commit_message_search.go b/git/commit/search/commit_message_search.go
index 5598e94..853f1cf 100644
--- a/git/commit/search/commit_message_search.go
+++ b/git/commit/search/commit_message_search.go
@@ -11,10 +11,6 @@ type commitMessageSearch struct {
 	commits []git.Commit
 }
 
-func (m commitMessageSearch) New(commits []git.Commit) Search {
-	return commitMessageSearch{commits: commits}
-}
-
 func (m commitMessageSearch) Search(searchKey string) []git.Commit {
 	var (
 		matchingCommits []git.Commit
diff --git a/git/commit/search/commit_message_search_test.go b/git/commit/search/commit_message_search_test.go
new file mode 100644
index 0000000..2551ac7
--- /dev/null
+++ b/git/commit/search/commit_message_search_test.go
@@ -0,0 +1,37 @@
+package search
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/commit/search/test_utils"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type CommitMessageSearchTestSuite struct {
+	suite.Suite
+	allCommits []git2go.Commit
+	search     Search
+}
+
+func TestCommitMessageSearchTestSuite(t *testing.T) {
+	suite.Run(t, new(CommitMessageSearchTestSuite))
+}
+
+func (suite *CommitMessageSearchTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	repo := middleware.NewRepository(r)
+	suite.allCommits = test_utils.GetAllTestCommitLogs(repo)
+	suite.search = GetSearchAction("message", suite.allCommits)
+}
+
+func (suite *CommitMessageSearchTestSuite) TestSearch_ShouldReturnCommitsMatchingTheMessage() {
+	commits := suite.search.Search("")
+
+	suite.NotZero(len(commits))
+}
