Improve pull request list api (#34052)

The pull request list API is slow, for every pull request, it needs to
open a git repository. Assume it has 30 records, there will be 30 sub
processes back because every repository will open a git cat-file --batch
sub process. This PR use base git repository to get the head commit id
rather than read it from head repository to avoid open any head git
repository.
pull/34031/head^2
Lunny Xiao 2025-03-31 12:54:31 -07:00 committed by GitHub
parent 342432e52a
commit a2e8a289b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 56 deletions

View File

@ -173,6 +173,18 @@ func GetBranch(ctx context.Context, repoID int64, branchName string) (*Branch, e
return &branch, nil return &branch, nil
} }
// IsBranchExist returns true if the branch exists in the repository.
func IsBranchExist(ctx context.Context, repoID int64, branchName string) (bool, error) {
var branch Branch
has, err := db.GetEngine(ctx).Where("repo_id=?", repoID).And("name=?", branchName).Get(&branch)
if err != nil {
return false, err
} else if !has {
return false, nil
}
return !branch.IsDeleted, nil
}
func GetBranches(ctx context.Context, repoID int64, branchNames []string, includeDeleted bool) ([]*Branch, error) { func GetBranches(ctx context.Context, repoID int64, branchNames []string, includeDeleted bool) ([]*Branch, error) {
branches := make([]*Branch, 0, len(branchNames)) branches := make([]*Branch, 0, len(branchNames))

View File

@ -389,7 +389,7 @@ func ToAPIPullRequests(ctx context.Context, baseRepo *repo_model.Repository, prs
}, },
Head: &api.PRBranchInfo{ Head: &api.PRBranchInfo{
Name: pr.HeadBranch, Name: pr.HeadBranch,
Ref: fmt.Sprintf("%s%d/head", git.PullPrefix, pr.Index), Ref: pr.GetGitRefName(),
RepoID: -1, RepoID: -1,
}, },
} }
@ -422,72 +422,43 @@ func ToAPIPullRequests(ctx context.Context, baseRepo *repo_model.Repository, prs
return nil, err return nil, err
} }
} }
if baseBranch != nil { if baseBranch != nil {
apiPullRequest.Base.Sha = baseBranch.CommitID apiPullRequest.Base.Sha = baseBranch.CommitID
} }
if pr.Flow == issues_model.PullRequestFlowAGit { // pull request head branch, both repository and branch could not exist
apiPullRequest.Head.Sha, err = gitRepo.GetRefCommitID(pr.GetGitRefName()) if pr.HeadRepo != nil {
apiPullRequest.Head.RepoID = pr.HeadRepo.ID
exist, err := git_model.IsBranchExist(ctx, pr.HeadRepo.ID, pr.HeadBranch)
if err != nil { if err != nil {
log.Error("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err) log.Error("IsBranchExist[%d]: %v", pr.HeadRepo.ID, err)
return nil, err return nil, err
} }
apiPullRequest.Head.RepoID = pr.BaseRepoID if exist {
apiPullRequest.Head.Repository = apiPullRequest.Base.Repository apiPullRequest.Head.Ref = pr.HeadBranch
apiPullRequest.Head.Name = "" }
}
if apiPullRequest.Head.Ref == "" {
apiPullRequest.Head.Ref = pr.GetGitRefName()
} }
var headGitRepo *git.Repository if pr.HeadRepoID == pr.BaseRepoID {
if pr.HeadRepo != nil && pr.Flow == issues_model.PullRequestFlowGithub { apiPullRequest.Head.Repository = apiPullRequest.Base.Repository
if pr.HeadRepoID == pr.BaseRepoID { } else {
apiPullRequest.Head.RepoID = pr.HeadRepo.ID p, err := access_model.GetUserRepoPermission(ctx, pr.HeadRepo, doer)
apiPullRequest.Head.Repository = apiRepo if err != nil {
headGitRepo = gitRepo log.Error("GetUserRepoPermission[%d]: %v", pr.HeadRepoID, err)
} else { p.AccessMode = perm.AccessModeNone
p, err := access_model.GetUserRepoPermission(ctx, pr.HeadRepo, doer)
if err != nil {
log.Error("GetUserRepoPermission[%d]: %v", pr.HeadRepoID, err)
p.AccessMode = perm.AccessModeNone
}
apiPullRequest.Head.RepoID = pr.HeadRepo.ID
apiPullRequest.Head.Repository = ToRepo(ctx, pr.HeadRepo, p)
headGitRepo, err = gitrepo.OpenRepository(ctx, pr.HeadRepo)
if err != nil {
log.Error("OpenRepository[%s]: %v", pr.HeadRepo.RepoPath(), err)
return nil, err
}
defer headGitRepo.Close()
} }
apiPullRequest.Head.Repository = ToRepo(ctx, pr.HeadRepo, p)
}
headBranch, err := headGitRepo.GetBranch(pr.HeadBranch) if pr.Flow == issues_model.PullRequestFlowAGit {
if err != nil && !git.IsErrBranchNotExist(err) { apiPullRequest.Head.Name = ""
log.Error("GetBranch[%s]: %v", pr.HeadBranch, err) }
return nil, err apiPullRequest.Head.Sha, err = gitRepo.GetRefCommitID(pr.GetGitRefName())
} if err != nil {
log.Error("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
if git.IsErrBranchNotExist(err) {
headCommitID, err := headGitRepo.GetRefCommitID(apiPullRequest.Head.Ref)
if err != nil && !git.IsErrNotExist(err) {
log.Error("GetCommit[%s]: %v", pr.HeadBranch, err)
return nil, err
}
if err == nil {
apiPullRequest.Head.Sha = headCommitID
}
} else {
commit, err := headBranch.GetCommit()
if err != nil && !git.IsErrNotExist(err) {
log.Error("GetCommit[%s]: %v", headBranch.Name, err)
return nil, err
}
if err == nil {
apiPullRequest.Head.Ref = pr.HeadBranch
apiPullRequest.Head.Sha = commit.ID.String()
}
}
} }
if len(apiPullRequest.Head.Sha) == 0 && len(apiPullRequest.Head.Ref) != 0 { if len(apiPullRequest.Head.Sha) == 0 && len(apiPullRequest.Head.Ref) != 0 {