drone/gitrpc/internal/service/branch.go
Enver Bisevac 578dd13d8d [maint] eb/gitrpc refactor (#51)
* pull/push impl done

* Basic auth for harness

* gitrpc as top level package

* New ctor for package

* gitrpcserver instead of server2
2022-11-03 13:17:03 +01:00

121 lines
3.6 KiB
Go

// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package service
import (
"context"
"fmt"
"github.com/harness/gitness/gitrpc/internal/gitea"
"github.com/harness/gitness/gitrpc/internal/types"
"github.com/harness/gitness/gitrpc/rpc"
"github.com/rs/zerolog/log"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var listBranchesRefFields = []types.GitReferenceField{types.GitReferenceFieldRefName, types.GitReferenceFieldObjectName}
func (s RepositoryService) ListBranches(request *rpc.ListBranchesRequest,
stream rpc.RepositoryService_ListBranchesServer) error {
ctx := stream.Context()
repoPath := s.getFullPathForRepo(request.GetRepoUid())
// get all required information from git refrences
branches, err := s.listBranchesLoadReferenceData(ctx, repoPath, request)
if err != nil {
return err
}
// get commits if needed (single call for perf savings: 1s-4s vs 5s-20s)
if request.GetIncludeCommit() {
commitSHAs := make([]string, len(branches))
for i := range branches {
commitSHAs[i] = branches[i].Sha
}
var gitCommits []types.Commit
gitCommits, err = s.adapter.GetCommits(ctx, repoPath, commitSHAs)
if err != nil {
return status.Errorf(codes.Internal, "failed to get commits: %v", err)
}
for i := range gitCommits {
branches[i].Commit, err = mapGitCommit(&gitCommits[i])
if err != nil {
return err
}
}
}
// send out all branches
for _, branch := range branches {
err = stream.Send(&rpc.ListBranchesResponse{
Branch: branch,
})
if err != nil {
return status.Errorf(codes.Internal, "failed to send branch: %v", err)
}
}
return nil
}
func (s RepositoryService) listBranchesLoadReferenceData(ctx context.Context,
repoPath string, request *rpc.ListBranchesRequest) ([]*rpc.Branch, error) {
// TODO: can we be smarter with slice allocation
branches := make([]*rpc.Branch, 0, 16)
handler := listBranchesWalkReferencesHandler(&branches)
instructor, endsAfter, err := wrapInstructorWithOptionalPagination(
gitea.DefaultInstructor, // branches only have one target type, default instructor is enough
request.GetPage(),
request.GetPageSize())
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid pagination details: %v", err)
}
opts := &types.WalkReferencesOptions{
Patterns: createReferenceWalkPatternsFromQuery(gitReferenceNamePrefixBranch, request.GetQuery()),
Sort: mapListBranchesSortOption(request.Sort),
Order: mapSortOrder(request.Order),
Fields: listBranchesRefFields,
Instructor: instructor,
// we don't do any post-filtering, restrict git to only return as many elements as pagination needs.
MaxWalkDistance: endsAfter,
}
err = s.adapter.WalkReferences(ctx, repoPath, handler, opts)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get branch references: %v", err)
}
log.Trace().Msgf("git adapter returned %d branches", len(branches))
return branches, nil
}
func listBranchesWalkReferencesHandler(branches *[]*rpc.Branch) types.WalkReferencesHandler {
return func(e types.WalkReferencesEntry) error {
fullRefName, ok := e[types.GitReferenceFieldRefName]
if !ok {
return fmt.Errorf("entry missing reference name")
}
objectSHA, ok := e[types.GitReferenceFieldObjectName]
if !ok {
return fmt.Errorf("entry missing object sha")
}
branch := &rpc.Branch{
Name: fullRefName[len(gitReferenceNamePrefixBranch):],
Sha: objectSHA,
}
// TODO: refactor to not use slice pointers?
*branches = append(*branches, branch)
return nil
}
}