Make gogit Repository.GetBranchNames consistent (#28348) (#28386)

Backport #28348 by @AdamMajer

nogogit GetBranchNames() lists branches sorted in reverse commit date
order. On the other hand the gogit implementation doesn't apply any
ordering resulting in unpredictable behaviour. In my case, the unit
tests requiring particular order fail

    repo_branch_test.go:24:
                Error Trace:
               ./gitea/modules/git/repo_branch_test.go:24
                Error:          elements differ

                                extra elements in list A:
                                ([]interface {}) (len=1) {
                                 (string) (len=6) "master"
                                }

                                extra elements in list B:
                                ([]interface {}) (len=1) {
                                 (string) (len=7) "branch1"
                                }

                                listA:
                                ([]string) (len=2) {
                                 (string) (len=6) "master",
                                 (string) (len=7) "branch2"
                                }

                                listB:
                                ([]string) (len=2) {
                                 (string) (len=7) "branch1",
                                 (string) (len=7) "branch2"
                                }
                Test:           TestRepository_GetBranches

To fix this, we sort branches based on their commit date in gogit
implementation.

Fixes: #28318

Co-authored-by: Adam Majer <amajer@suse.de>
This commit is contained in:
Giteabot 2023-12-08 02:03:27 +08:00 committed by GitHub
parent b56a9f6ded
commit 272ae03341
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -8,6 +8,7 @@ package git
import ( import (
"context" "context"
"sort"
"strings" "strings"
"github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing"
@ -52,32 +53,46 @@ func (repo *Repository) IsBranchExist(name string) bool {
// GetBranches returns branches from the repository, skipping "skip" initial branches and // GetBranches returns branches from the repository, skipping "skip" initial branches and
// returning at most "limit" branches, or all branches if "limit" is 0. // returning at most "limit" branches, or all branches if "limit" is 0.
// Branches are returned with sort of `-commiterdate` as the nogogit
// implementation. This requires full fetch, sort and then the
// skip/limit applies later as gogit returns in undefined order.
func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) { func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
var branchNames []string type BranchData struct {
name string
committerDate int64
}
var branchData []BranchData
branches, err := repo.gogitRepo.Branches() branchIter, err := repo.gogitRepo.Branches()
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
i := 0 _ = branchIter.ForEach(func(branch *plumbing.Reference) error {
count := 0 obj, err := repo.gogitRepo.CommitObject(branch.Hash())
_ = branches.ForEach(func(branch *plumbing.Reference) error { if err != nil {
count++ // skip branch if can't find commit
if i < skip {
i++
return nil
} else if limit != 0 && count > skip+limit {
return nil return nil
} }
branchNames = append(branchNames, strings.TrimPrefix(branch.Name().String(), BranchPrefix)) branchData = append(branchData, BranchData{strings.TrimPrefix(branch.Name().String(), BranchPrefix), obj.Committer.When.Unix()})
return nil return nil
}) })
// TODO: Sort? sort.Slice(branchData, func(i, j int) bool {
return !(branchData[i].committerDate < branchData[j].committerDate)
})
return branchNames, count, nil var branchNames []string
maxPos := len(branchData)
if limit > 0 {
maxPos = min(skip+limit, maxPos)
}
for i := skip; i < maxPos; i++ {
branchNames = append(branchNames, branchData[i].name)
}
return branchNames, len(branchData), nil
} }
// WalkReferences walks all the references from the repository // WalkReferences walks all the references from the repository