mirror of
https://github.com/grdl/git-get.git
synced 2026-02-07 16:59:16 +00:00
Add CloneRepo function and unit tests for cloned repos status
This commit is contained in:
45
branch.go
45
branch.go
@@ -15,7 +15,7 @@ type BranchStatus struct {
|
|||||||
Behind int
|
Behind int
|
||||||
}
|
}
|
||||||
|
|
||||||
func Branches(repo *git.Repository) ([]BranchStatus, error) {
|
func Branches(repo *git.Repository) (map[string]BranchStatus, error) {
|
||||||
iter, err := repo.NewBranchIterator(git.BranchAll)
|
iter, err := repo.NewBranchIterator(git.BranchAll)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Failed creating branch iterator")
|
return nil, errors.Wrap(err, "Failed creating branch iterator")
|
||||||
@@ -31,14 +31,14 @@ func Branches(repo *git.Repository) ([]BranchStatus, error) {
|
|||||||
return nil, errors.Wrap(err, "Failed iterating over branches")
|
return nil, errors.Wrap(err, "Failed iterating over branches")
|
||||||
}
|
}
|
||||||
|
|
||||||
var statuses []BranchStatus
|
statuses := make(map[string]BranchStatus)
|
||||||
for _, branch := range branches {
|
for _, branch := range branches {
|
||||||
status, err := NewBranchStatus(repo, branch)
|
status, err := NewBranchStatus(repo, branch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: handle error
|
// TODO: Handle error. We should tell user that we couldn't read status of that branch but probably shouldn't exit
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
statuses = append(statuses, status)
|
statuses[status.Name] = status
|
||||||
}
|
}
|
||||||
|
|
||||||
return statuses, nil
|
return statuses, nil
|
||||||
@@ -53,31 +53,38 @@ func NewBranchStatus(repo *git.Repository, branch *git.Branch) (BranchStatus, er
|
|||||||
}
|
}
|
||||||
status.Name = name
|
status.Name = name
|
||||||
|
|
||||||
status.IsRemote = branch.IsRemote()
|
// If branch is a remote one, return immediately. Upstream can only be found for local branches.
|
||||||
|
if branch.IsRemote() {
|
||||||
|
status.IsRemote = true
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
upstream, err := branch.Upstream()
|
upstream, err := branch.Upstream()
|
||||||
if err != nil && !git.IsErrorCode(err, git.ErrNotFound) {
|
if err != nil && !git.IsErrorCode(err, git.ErrNotFound) {
|
||||||
return status, errors.Wrap(err, "Failed getting branch upstream")
|
return status, errors.Wrap(err, "Failed getting branch upstream")
|
||||||
}
|
}
|
||||||
|
|
||||||
if upstream != nil {
|
// If there's no upstream, return immediately. Ahead/Behind can only be found when upstream exists.
|
||||||
status.HasUpstream = true
|
if upstream == nil {
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
ahead, behind, err := repo.AheadBehind(branch.Target(), upstream.Target())
|
status.HasUpstream = true
|
||||||
if err != nil {
|
|
||||||
return status, errors.Wrap(err, "Failed getting ahead/behind information")
|
|
||||||
}
|
|
||||||
|
|
||||||
status.Ahead = ahead
|
ahead, behind, err := repo.AheadBehind(branch.Target(), upstream.Target())
|
||||||
status.Behind = behind
|
if err != nil {
|
||||||
|
return status, errors.Wrap(err, "Failed getting ahead/behind information")
|
||||||
|
}
|
||||||
|
|
||||||
if ahead > 0 {
|
status.Ahead = ahead
|
||||||
status.NeedsPush = true
|
status.Behind = behind
|
||||||
}
|
|
||||||
|
|
||||||
if behind > 0 {
|
if ahead > 0 {
|
||||||
status.NeedsPull = true
|
status.NeedsPush = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if behind > 0 {
|
||||||
|
status.NeedsPull = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return status, nil
|
return status, nil
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,3 +30,49 @@ func TestNewLocalBranch(t *testing.T) {
|
|||||||
t.Errorf("Wrong branch status, got %+v; want %+v", status, want)
|
t.Errorf("Wrong branch status, got %+v; want %+v", status, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClonedBranches(t *testing.T) {
|
||||||
|
origin := newTestRepo(t)
|
||||||
|
createFile(t, origin, "file")
|
||||||
|
stageFile(t, origin, "file")
|
||||||
|
createCommit(t, origin, "Initial commit")
|
||||||
|
|
||||||
|
repo, err := CloneRepo(origin.Path(), newTempDir(t))
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
createBranch(t, repo, "branch")
|
||||||
|
|
||||||
|
branches, err := Branches(repo)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
master := branches["master"]
|
||||||
|
wantMaster := BranchStatus{
|
||||||
|
Name: "master",
|
||||||
|
IsRemote: false,
|
||||||
|
HasUpstream: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
originMaster := branches["origin/master"]
|
||||||
|
wantOriginMaster := BranchStatus{
|
||||||
|
Name: "origin/master",
|
||||||
|
IsRemote: true,
|
||||||
|
HasUpstream: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
branch := branches["branch"]
|
||||||
|
wantBranch := BranchStatus{
|
||||||
|
Name: "branch",
|
||||||
|
IsRemote: false,
|
||||||
|
HasUpstream: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(master, wantMaster) {
|
||||||
|
t.Errorf("Wrong branch status, got %+v; want %+v", master, wantMaster)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(originMaster, wantOriginMaster) {
|
||||||
|
t.Errorf("Wrong branch status, got %+v; want %+v", originMaster, wantOriginMaster)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(branch, wantBranch) {
|
||||||
|
t.Errorf("Wrong branch status, got %+v; want %+v", branch, wantBranch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,24 +18,26 @@ func checkFatal(t *testing.T, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanupRepo(t *testing.T, repo *git.Repository) {
|
func newTempDir(t *testing.T) string {
|
||||||
err := os.RemoveAll(repo.Workdir())
|
dir, err := ioutil.TempDir("", "git-get-repo-")
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed cleaning up repo")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTestRepo(t *testing.T) *git.Repository {
|
|
||||||
dir, err := ioutil.TempDir("", "test-repo-")
|
|
||||||
checkFatal(t, errors.Wrap(err, "Failed creating test repo directory"))
|
checkFatal(t, errors.Wrap(err, "Failed creating test repo directory"))
|
||||||
|
|
||||||
repo, err := git.InitRepository(dir, false)
|
|
||||||
checkFatal(t, errors.Wrap(err, "Failed initializing a temp repo"))
|
|
||||||
|
|
||||||
// Automatically remove repo when test is over
|
// Automatically remove repo when test is over
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
cleanupRepo(t, repo)
|
err := os.RemoveAll(dir)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed cleaning up repo")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestRepo(t *testing.T) *git.Repository {
|
||||||
|
dir := newTempDir(t)
|
||||||
|
repo, err := git.InitRepository(dir, false)
|
||||||
|
checkFatal(t, errors.Wrap(err, "Failed initializing a temp repo"))
|
||||||
|
|
||||||
return repo
|
return repo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
repo.go
Normal file
20
repo.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
git "github.com/libgit2/git2go/v30"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CloneRepo(url string, path string) (*git.Repository, error) {
|
||||||
|
options := &git.CloneOptions{
|
||||||
|
CheckoutOpts: nil,
|
||||||
|
FetchOptions: nil,
|
||||||
|
Bare: false,
|
||||||
|
CheckoutBranch: "",
|
||||||
|
RemoteCreateCallback: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
repo, err := git.Clone(url, path, options)
|
||||||
|
return repo, errors.Wrap(err, "Failed cloning repo")
|
||||||
|
}
|
||||||
@@ -140,6 +140,28 @@ func TestStatusWithMultipleCommits(t *testing.T) {
|
|||||||
if len(entries) != 0 {
|
if len(entries) != 0 {
|
||||||
t.Errorf("Repo with no uncommitted files should have no status entries")
|
t.Errorf("Repo with no uncommitted files should have no status entries")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status, err := NewRepoStatus(repo.Workdir())
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
want := RepoStatus{
|
||||||
|
HasUntrackedFiles: false,
|
||||||
|
HasUncommittedChanges: false,
|
||||||
|
BranchStatuses: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(status, want) {
|
||||||
|
t.Errorf("Wrong repo status, got %+v; want %+v", status, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStatusCloned(t *testing.T) {
|
||||||
|
origin := newTestRepo(t)
|
||||||
|
dir := newTempDir(t)
|
||||||
|
|
||||||
|
repo, err := CloneRepo(origin.Path(), dir)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
status, err := NewRepoStatus(repo.Workdir())
|
status, err := NewRepoStatus(repo.Workdir())
|
||||||
checkFatal(t, err)
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user