Skip to content
This repository has been archived by the owner on Apr 26, 2021. It is now read-only.

Implement methods to get branches in a repository (re #120 and #123) #124

Merged
merged 2 commits into from
Jul 23, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 69 additions & 6 deletions repository/mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type MockContentRetriever struct {
LastPath string
ResultContents []byte
Tree []map[string]string
Refs []map[string]string
LookPathError error
OutputError error
}
Expand All @@ -25,11 +26,9 @@ func (r *MockContentRetriever) GetContents(repo, ref, path string) ([]byte, erro
if r.LookPathError != nil {
return nil, r.LookPathError
}

if r.OutputError != nil {
return nil, r.OutputError
}

r.LastRef = ref
return r.ResultContents, nil
}
Expand All @@ -38,11 +37,9 @@ func (r *MockContentRetriever) GetArchive(repo, ref string, format ArchiveFormat
if r.LookPathError != nil {
return nil, r.LookPathError
}

if r.OutputError != nil {
return nil, r.OutputError
}

r.LastRef = ref
r.LastFormat = format
return r.ResultContents, nil
Expand Down Expand Up @@ -106,16 +103,82 @@ func CreateTestRepository(tmp_path string, repo string, file string, content str
return cleanup, err
}

func CreateBranchesOnTestRepository(tmp_path string, repo string, file string, content string, branches ...string) error {
testPath := path.Join(tmp_path, repo+".git")
gitPath, err := exec.LookPath("git")
if err != nil {
return err
}
cmd := exec.Command(gitPath, "status")
cmd.Dir = testPath
err = cmd.Run()
if err != nil {
return err
}
for _, branch := range branches {
fp, err := os.OpenFile(path.Join(testPath, file), os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer fp.Close()
_, err = fp.WriteString("such string")
if err != nil {
return err
}
cmd = exec.Command(gitPath, "checkout", "-b", branch)
cmd.Dir = testPath
err = cmd.Run()
if err != nil {
return err
}
cmd = exec.Command(gitPath, "add", ".")
cmd.Dir = testPath
err = cmd.Run()
if err != nil {
return err
}
if len(content) > 0 {
cmd = exec.Command(gitPath, "commit", "-m", content+" on "+branch)
} else {
cmd = exec.Command(gitPath, "commit", "-m", "", "--allow-empty-message")
}
cmd.Dir = testPath
err = cmd.Run()
if err != nil {
return err
}
}
return err
}

func (r *MockContentRetriever) GetTree(repo, ref, path string) ([]map[string]string, error) {
if r.LookPathError != nil {
return nil, r.LookPathError
}

if r.OutputError != nil {
return nil, r.OutputError
}

r.LastRef = ref
r.LastPath = path
return r.Tree, nil
}

func (r *MockContentRetriever) GetForEachRef(repo, pattern string) ([]map[string]string, error) {
if r.LookPathError != nil {
return nil, r.LookPathError
}
if r.OutputError != nil {
return nil, r.OutputError
}
return r.Refs, nil
}

func (r *MockContentRetriever) GetBranch(repo string) ([]map[string]string, error) {
if r.LookPathError != nil {
return nil, r.LookPathError
}
if r.OutputError != nil {
return nil, r.OutputError
}
return r.Refs, nil
}
70 changes: 70 additions & 0 deletions repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ type ContentRetriever interface {
GetContents(repo, ref, path string) ([]byte, error)
GetArchive(repo, ref string, format ArchiveFormat) ([]byte, error)
GetTree(repo, ref, path string) ([]map[string]string, error)
GetForEachRef(repo, pattern string) ([]map[string]string, error)
GetBranch(repo string) ([]map[string]string, error)
}

var Retriever ContentRetriever
Expand Down Expand Up @@ -349,6 +351,66 @@ func (*GitContentRetriever) GetTree(repo, ref, path string) ([]map[string]string
return objects, nil
}

func (*GitContentRetriever) GetForEachRef(repo, pattern string) ([]map[string]string, error) {
var ref, name, commiterName, commiterEmail, commiterDate, authorName, authorEmail, authorDate, subject string
gitPath, err := exec.LookPath("git")
if err != nil {
return nil, fmt.Errorf("Error when trying to obtain the branches of repository %s (%s).", repo, err)
}
cwd := barePath(repo)
repoExists, err := exists(cwd)
if err != nil || !repoExists {
return nil, fmt.Errorf("Error when trying to obtain the branches of repository %s (Repository does not exist).", repo)
}
cmd := exec.Command(gitPath, "for-each-ref", "--sort=-committerdate", "--format", "%(objectname)%09%(refname)%09%(committername)%09%(committeremail)%09%(committerdate)%09%(authorname)%09%(authoremail)%09%(authordate)%09%(contents:subject)", pattern)
cmd.Dir = cwd
out, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("Error when trying to obtain the branches of repository %s (%s).", repo, err)
}
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
objectCount := len(lines)
objects := make([]map[string]string, objectCount)
objectCount = 0
for _, line := range lines {
if strings.TrimSpace(line) == "" {
continue
}
fields := strings.Split(line, "\t")
if len(fields) > 4 { // let there be commits with empty subject
ref = fields[0]
name = strings.Replace(fields[1], pattern, "", 1)
commiterName = fields[2]
commiterEmail = fields[3]
commiterDate = fields[4]
authorName = fields[5]
authorEmail = fields[6]
authorDate = fields[7]
subject = strings.Join(fields[8:], "\t") // let there be subjects with \t
} else {
return nil, fmt.Errorf("Error when trying to obtain the branches of repository %s (Invalid git for-each-ref output [%s]).", repo, out)
}
object := make(map[string]string)
object["ref"] = ref
object["name"] = name
object["commiterName"] = commiterName
object["commiterEmail"] = commiterEmail
object["commiterDate"] = commiterDate
object["authorName"] = authorName
object["authorEmail"] = authorEmail
object["authorDate"] = authorDate
object["subject"] = subject
objects[objectCount] = object
objectCount++
}
return objects, nil
}

func (*GitContentRetriever) GetBranch(repo string) ([]map[string]string, error) {
branches, err := retriever().GetForEachRef(repo, "refs/heads/")
return branches, err
}

func retriever() ContentRetriever {
if Retriever == nil {
Retriever = &GitContentRetriever{}
Expand All @@ -371,3 +433,11 @@ func GetArchive(repo, ref string, format ArchiveFormat) ([]byte, error) {
func GetTree(repo, ref, path string) ([]map[string]string, error) {
return retriever().GetTree(repo, ref, path)
}

func GetForEachRef(repo, pattern string) ([]map[string]string, error) {
return retriever().GetForEachRef(repo, pattern)
}

func GetBranch(repo string) ([]map[string]string, error) {
return retriever().GetBranch(repo)
}
73 changes: 73 additions & 0 deletions repository/repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -803,3 +803,76 @@ func (s *S) TestGetTreeIntegrationWithInvalidRef(c *gocheck.C) {
_, err := GetTree(repo, "VeryInvalid", "very missing")
c.Assert(err, gocheck.ErrorMatches, "^Error when trying to obtain tree very missing on ref VeryInvalid of repository gandalf-test-repo \\(exit status 128\\)\\.$")
}

func (s *S) TestGetBranchIntegration(c *gocheck.C) {
oldBare := bare
bare = "/tmp"
repo := "gandalf-test-repo"
file := "README"
content := "will bark"
cleanUp, errCreate := CreateTestRepository(bare, repo, file, content)
defer func() {
cleanUp()
bare = oldBare
}()
c.Assert(errCreate, gocheck.IsNil)
errCreateBranches := CreateBranchesOnTestRepository(bare, repo, file, content, "doge_bites", "doge_barks")
c.Assert(errCreateBranches, gocheck.IsNil)
branches, err := GetBranch(repo)
c.Assert(err, gocheck.IsNil)
c.Assert(len(branches), gocheck.Equals, 3)
c.Assert(branches[0]["ref"], gocheck.Matches, "[a-f0-9]{40}")
c.Assert(branches[0]["name"], gocheck.Equals, "doge_barks")
c.Assert(branches[0]["commiterName"], gocheck.Equals, "doge")
c.Assert(branches[0]["commiterEmail"], gocheck.Equals, "<much@email.com>")
c.Assert(branches[0]["authorName"], gocheck.Equals, "doge")
c.Assert(branches[0]["authorEmail"], gocheck.Equals, "<much@email.com>")
c.Assert(branches[0]["subject"], gocheck.Equals, "will bark on doge_barks")
c.Assert(branches[1]["ref"], gocheck.Matches, "[a-f0-9]{40}")
c.Assert(branches[1]["name"], gocheck.Equals, "doge_bites")
c.Assert(branches[1]["commiterName"], gocheck.Equals, "doge")
c.Assert(branches[1]["commiterEmail"], gocheck.Equals, "<much@email.com>")
c.Assert(branches[1]["authorName"], gocheck.Equals, "doge")
c.Assert(branches[1]["authorEmail"], gocheck.Equals, "<much@email.com>")
c.Assert(branches[1]["subject"], gocheck.Equals, "will bark on doge_bites")
c.Assert(branches[2]["ref"], gocheck.Matches, "[a-f0-9]{40}")
c.Assert(branches[2]["name"], gocheck.Equals, "master")
c.Assert(branches[2]["commiterName"], gocheck.Equals, "doge")
c.Assert(branches[2]["commiterEmail"], gocheck.Equals, "<much@email.com>")
c.Assert(branches[2]["authorName"], gocheck.Equals, "doge")
c.Assert(branches[2]["authorEmail"], gocheck.Equals, "<much@email.com>")
c.Assert(branches[2]["subject"], gocheck.Equals, "will bark")
}

func (s *S) TestGetBranchIntegrationEmptySubject(c *gocheck.C) {
oldBare := bare
bare = "/tmp"
repo := "gandalf-test-repo"
file := "README"
content := ""
cleanUp, errCreate := CreateTestRepository(bare, repo, file, content)
defer func() {
cleanUp()
bare = oldBare
}()
c.Assert(errCreate, gocheck.IsNil)
errCreateBranches := CreateBranchesOnTestRepository(bare, repo, file, content, "doge_howls")
c.Assert(errCreateBranches, gocheck.IsNil)
branches, err := GetBranch(repo)
c.Assert(err, gocheck.IsNil)
c.Assert(len(branches), gocheck.Equals, 2)
c.Assert(branches[0]["ref"], gocheck.Matches, "[a-f0-9]{40}")
c.Assert(branches[0]["name"], gocheck.Equals, "doge_howls")
c.Assert(branches[0]["commiterName"], gocheck.Equals, "doge")
c.Assert(branches[0]["commiterEmail"], gocheck.Equals, "<much@email.com>")
c.Assert(branches[0]["authorName"], gocheck.Equals, "doge")
c.Assert(branches[0]["authorEmail"], gocheck.Equals, "<much@email.com>")
c.Assert(branches[0]["subject"], gocheck.Equals, "")
c.Assert(branches[1]["ref"], gocheck.Matches, "[a-f0-9]{40}")
c.Assert(branches[1]["name"], gocheck.Equals, "master")
c.Assert(branches[1]["commiterName"], gocheck.Equals, "doge")
c.Assert(branches[1]["commiterEmail"], gocheck.Equals, "<much@email.com>")
c.Assert(branches[1]["authorName"], gocheck.Equals, "doge")
c.Assert(branches[1]["authorEmail"], gocheck.Equals, "<much@email.com>")
c.Assert(branches[1]["subject"], gocheck.Equals, "")
}