Move GetDiverging functions to gitrepo (#35524)

Extracted from #35469

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Lunny Xiao
2025-09-26 08:15:42 -07:00
committed by GitHub
parent 8ad2a538da
commit 7bf2972379
16 changed files with 220 additions and 176 deletions

View File

@@ -50,7 +50,7 @@ var (
func markPullRequestStatusAsChecking(ctx context.Context, pr *issues_model.PullRequest) bool {
pr.Status = issues_model.PullRequestStatusChecking
err := pr.UpdateColsIfNotMerged(ctx, "status")
_, err := pr.UpdateColsIfNotMerged(ctx, "status")
if err != nil {
log.Error("UpdateColsIfNotMerged failed, pr: %-v, err: %v", pr, err)
return false
@@ -256,7 +256,7 @@ func markPullRequestAsMergeable(ctx context.Context, pr *issues_model.PullReques
return
}
if err := pr.UpdateColsIfNotMerged(ctx, "merge_base", "status", "conflicted_files", "changed_protected_files"); err != nil {
if _, err := pr.UpdateColsIfNotMerged(ctx, "merge_base", "status", "conflicted_files", "changed_protected_files"); err != nil {
log.Error("Update[%-v]: %v", pr, err)
}

View File

@@ -99,13 +99,6 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error {
return err
}
divergence, err := git.GetDivergingCommits(ctx, prCtx.tmpBasePath, baseBranch, trackingBranch)
if err != nil {
return err
}
pr.CommitsAhead = divergence.Ahead
pr.CommitsBehind = divergence.Behind
assigneeCommentMap := make(map[int64]*issues_model.Comment)
var reviewNotifiers []*issue_service.ReviewRequestNotifier
@@ -134,6 +127,12 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error {
return err
}
// Update Commit Divergence
err = syncCommitDivergence(ctx, pr)
if err != nil {
return err
}
// add first push codes comment
if _, err := CreatePushPullComment(ctx, issue.Poster, pr, git.BranchPrefix+pr.BaseBranch, pr.GetGitHeadRefName(), false); err != nil {
return err
@@ -287,25 +286,21 @@ func ChangeTargetBranch(ctx context.Context, pr *issues_model.PullRequest, doer
pr.Status = issues_model.PullRequestStatusMergeable
}
// Update Commit Divergence
divergence, err := GetDiverging(ctx, pr)
if err != nil {
return err
}
pr.CommitsAhead = divergence.Ahead
pr.CommitsBehind = divergence.Behind
// add first push codes comment
baseGitRepo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo)
if err != nil {
return err
}
defer baseGitRepo.Close()
return db.WithTx(ctx, func(ctx context.Context) error {
if err := pr.UpdateColsIfNotMerged(ctx, "merge_base", "status", "conflicted_files", "changed_protected_files", "base_branch", "commits_ahead", "commits_behind"); err != nil {
// The UPDATE acquires the transaction lock, if the UPDATE succeeds, it should have updated one row (the "base_branch" is changed)
// If no row is updated, it means the PR has been merged or closed in the meantime
updated, err := pr.UpdateColsIfNotMerged(ctx, "merge_base", "status", "conflicted_files", "changed_protected_files", "base_branch")
if err != nil {
return err
}
if updated == 0 {
return util.ErrorWrap(util.ErrInvalidArgument, "pull request status has changed")
}
if err := syncCommitDivergence(ctx, pr); err != nil {
return fmt.Errorf("syncCommitDivergence: %w", err)
}
// Create comment
options := &issues_model.CreateCommentOptions{
@@ -372,15 +367,21 @@ func AddTestPullRequestTask(opts TestPullRequestOptions) {
// If you don't let it run all the way then you will lose data
// TODO: graceful: AddTestPullRequestTask needs to become a queue!
repo, err := repo_model.GetRepositoryByID(ctx, opts.RepoID)
if err != nil {
log.Error("GetRepositoryByID: %v", err)
return
}
// GetUnmergedPullRequestsByHeadInfo() only return open and unmerged PR.
prs, err := issues_model.GetUnmergedPullRequestsByHeadInfo(ctx, opts.RepoID, opts.Branch)
headBranchPRs, err := issues_model.GetUnmergedPullRequestsByHeadInfo(ctx, opts.RepoID, opts.Branch)
if err != nil {
log.Error("Find pull requests [head_repo_id: %d, head_branch: %s]: %v", opts.RepoID, opts.Branch, err)
return
}
for _, pr := range prs {
for _, pr := range headBranchPRs {
log.Trace("Updating PR[%d]: composing new test task", pr.ID)
pr.HeadRepo = repo // avoid loading again
if pr.Flow == issues_model.PullRequestFlowGithub {
if err := PushToBaseRepo(ctx, pr); err != nil {
log.Error("PushToBaseRepo: %v", err)
@@ -398,14 +399,14 @@ func AddTestPullRequestTask(opts TestPullRequestOptions) {
}
if opts.IsSync {
if err = prs.LoadAttributes(ctx); err != nil {
if err = headBranchPRs.LoadAttributes(ctx); err != nil {
log.Error("PullRequestList.LoadAttributes: %v", err)
}
if invalidationErr := checkForInvalidation(ctx, prs, opts.RepoID, opts.Doer, opts.Branch); invalidationErr != nil {
if invalidationErr := checkForInvalidation(ctx, headBranchPRs, opts.RepoID, opts.Doer, opts.Branch); invalidationErr != nil {
log.Error("checkForInvalidation: %v", invalidationErr)
}
if err == nil {
for _, pr := range prs {
for _, pr := range headBranchPRs {
objectFormat := git.ObjectFormatFromName(pr.BaseRepo.ObjectFormatName)
if opts.NewCommitID != "" && opts.NewCommitID != objectFormat.EmptyObjectID().String() {
changed, err := checkIfPRContentChanged(ctx, pr, opts.OldCommitID, opts.NewCommitID)
@@ -432,14 +433,8 @@ func AddTestPullRequestTask(opts TestPullRequestOptions) {
if err := issues_model.MarkReviewsAsNotStale(ctx, pr.IssueID, opts.NewCommitID); err != nil {
log.Error("MarkReviewsAsNotStale: %v", err)
}
divergence, err := GetDiverging(ctx, pr)
if err != nil {
log.Error("GetDiverging: %v", err)
} else {
err = pr.UpdateCommitDivergence(ctx, divergence.Ahead, divergence.Behind)
if err != nil {
log.Error("UpdateCommitDivergence: %v", err)
}
if err = syncCommitDivergence(ctx, pr); err != nil {
log.Error("syncCommitDivergence: %v", err)
}
}
@@ -459,24 +454,22 @@ func AddTestPullRequestTask(opts TestPullRequestOptions) {
}
log.Trace("AddTestPullRequestTask [base_repo_id: %d, base_branch: %s]: finding pull requests", opts.RepoID, opts.Branch)
prs, err = issues_model.GetUnmergedPullRequestsByBaseInfo(ctx, opts.RepoID, opts.Branch)
// The base repositories of baseBranchPRs are the same one (opts.RepoID)
baseBranchPRs, err := issues_model.GetUnmergedPullRequestsByBaseInfo(ctx, opts.RepoID, opts.Branch)
if err != nil {
log.Error("Find pull requests [base_repo_id: %d, base_branch: %s]: %v", opts.RepoID, opts.Branch, err)
return
}
for _, pr := range prs {
divergence, err := GetDiverging(ctx, pr)
for _, pr := range baseBranchPRs {
pr.BaseRepo = repo // avoid loading again
err = syncCommitDivergence(ctx, pr)
if err != nil {
if git_model.IsErrBranchNotExist(err) && !gitrepo.IsBranchExist(ctx, pr.HeadRepo, pr.HeadBranch) {
log.Warn("Cannot test PR %s/%d: head_branch %s no longer exists", pr.BaseRepo.Name, pr.IssueID, pr.HeadBranch)
if errors.Is(err, util.ErrNotExist) {
log.Warn("Cannot test PR %s/%d with base=%s head=%s: no longer exists", pr.BaseRepo.FullName(), pr.IssueID, pr.BaseBranch, pr.HeadBranch)
} else {
log.Error("GetDiverging: %v", err)
}
} else {
err = pr.UpdateCommitDivergence(ctx, divergence.Ahead, divergence.Behind)
if err != nil {
log.Error("UpdateCommitDivergence: %v", err)
log.Error("syncCommitDivergence: %v", err)
}
continue
}
StartPullRequestCheckDelayable(ctx, pr)
}
@@ -486,7 +479,7 @@ func AddTestPullRequestTask(opts TestPullRequestOptions) {
// checkIfPRContentChanged checks if diff to target branch has changed by push
// A commit can be considered to leave the PR untouched if the patch/diff with its merge base is unchanged
func checkIfPRContentChanged(ctx context.Context, pr *issues_model.PullRequest, oldCommitID, newCommitID string) (hasChanged bool, err error) {
prCtx, cancel, err := createTemporaryRepoForPR(ctx, pr)
prCtx, cancel, err := createTemporaryRepoForPR(ctx, pr) // FIXME: why it still needs to create a temp repo, since the alongside calls like GetDiverging doesn't do so anymore
if err != nil {
log.Error("CreateTemporaryRepoForPR %-v: %v", pr, err)
return false, err

View File

@@ -14,7 +14,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/globallock"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/repository"
@@ -34,17 +34,21 @@ func Update(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.
}
defer releaser()
diffCount, err := GetDiverging(ctx, pr)
if err != nil {
return err
} else if diffCount.Behind == 0 {
return fmt.Errorf("HeadBranch of PR %d is up to date", pr.Index)
}
if err := pr.LoadBaseRepo(ctx); err != nil {
log.Error("unable to load BaseRepo for %-v during update-by-merge: %v", pr, err)
return fmt.Errorf("unable to load BaseRepo for PR[%d] during update-by-merge: %w", pr.ID, err)
}
// TODO: FakePR: if the PR is a fake PR (for example: from Merge Upstream), then no need to check diverging
if pr.ID > 0 {
diffCount, err := gitrepo.GetDivergingCommits(ctx, pr.BaseRepo, pr.BaseBranch, pr.GetGitHeadRefName())
if err != nil {
return err
} else if diffCount.Behind == 0 {
return fmt.Errorf("HeadBranch of PR %d is up to date", pr.Index)
}
}
if err := pr.LoadHeadRepo(ctx); err != nil {
log.Error("unable to load HeadRepo for PR %-v during update-by-merge: %v", pr, err)
return fmt.Errorf("unable to load HeadRepo for PR[%d] during update-by-merge: %w", pr.ID, err)
@@ -172,18 +176,13 @@ func IsUserAllowedToUpdate(ctx context.Context, pull *issues_model.PullRequest,
return mergeAllowed, rebaseAllowed, nil
}
// GetDiverging determines how many commits a PR is ahead or behind the PR base branch
func GetDiverging(ctx context.Context, pr *issues_model.PullRequest) (*git.DivergeObject, error) {
log.Trace("GetDiverging[%-v]: compare commits", pr)
prCtx, cancel, err := createTemporaryRepoForPR(ctx, pr)
if err != nil {
if !git_model.IsErrBranchNotExist(err) {
log.Error("CreateTemporaryRepoForPR %-v: %v", pr, err)
}
return nil, err
func syncCommitDivergence(ctx context.Context, pr *issues_model.PullRequest) error {
if err := pr.LoadBaseRepo(ctx); err != nil {
return err
}
defer cancel()
diff, err := git.GetDivergingCommits(ctx, prCtx.tmpBasePath, baseBranch, trackingBranch)
return &diff, err
divergence, err := gitrepo.GetDivergingCommits(ctx, pr.BaseRepo, pr.BaseBranch, pr.GetGitHeadRefName())
if err != nil {
return err
}
return pr.UpdateCommitDivergence(ctx, divergence.Ahead, divergence.Behind)
}