Skip to content

Commit 9b92c18

Browse files
committed
improve create pull request head ref
1 parent 9bb08aa commit 9b92c18

File tree

9 files changed

+93
-131
lines changed

9 files changed

+93
-131
lines changed

models/issues/pull.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ type PullRequest struct {
138138
BaseRepoID int64 `xorm:"INDEX"`
139139
BaseRepo *repo_model.Repository `xorm:"-"`
140140
HeadBranch string
141-
HeadCommitID string `xorm:"-"`
142141
BaseBranch string
143142
MergeBase string `xorm:"VARCHAR(64)"`
144143
AllowMaintainerEdit bool `xorm:"NOT NULL DEFAULT false"`

routers/web/repo/issue_comment.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ func NewComment(ctx *context.Context) {
9696

9797
// Regenerate patch and test conflict.
9898
if pr == nil {
99-
issue.PullRequest.HeadCommitID = ""
10099
pull_service.StartPullRequestCheckImmediately(ctx, issue.PullRequest)
101100
}
102101

routers/web/repo/pull_review.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,12 @@ func UpdateViewedFiles(ctx *context.Context) {
318318

319319
// Expect the review to have been now if no head commit was supplied
320320
if data.HeadCommitSHA == "" {
321-
data.HeadCommitSHA = pull.HeadCommitID
321+
data.HeadCommitSHA, err = ctx.Repo.GitRepo.GetRefCommitID(pull.GetGitHeadRefName())
322+
if err != nil {
323+
log.Warn("Attempted to get ref commit id: %v", err)
324+
ctx.Resp.WriteHeader(http.StatusBadRequest)
325+
return
326+
}
322327
}
323328

324329
updatedFiles := make(map[string]pull_model.ViewedState, len(data.Files))

routers/web/repo/pull_review_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ func TestRenderConversation(t *testing.T) {
4141

4242
var preparedComment *issues_model.Comment
4343
run("prepare", func(t *testing.T, ctx *context.Context, resp *httptest.ResponseRecorder) {
44-
comment, err := pull.CreateCodeComment(ctx, pr.Issue.Poster, ctx.Repo.GitRepo, pr.Issue, 1, "content", "", false, 0, pr.HeadCommitID, nil)
44+
headCommitID, err := ctx.Repo.GitRepo.GetRefCommitID(pr.GetGitHeadRefName())
45+
assert.NoError(t, err)
46+
comment, err := pull.CreateCodeComment(ctx, pr.Issue.Poster, ctx.Repo.GitRepo, pr.Issue, 1, "content", "", false, 0, headCommitID, nil)
4547
require.NoError(t, err)
4648

4749
comment.Invalidated = true

services/agit/agit.go

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -142,21 +142,21 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
142142
}
143143

144144
pr := &issues_model.PullRequest{
145-
HeadRepoID: repo.ID,
146-
BaseRepoID: repo.ID,
147-
HeadBranch: headBranch,
148-
HeadCommitID: opts.NewCommitIDs[i],
149-
BaseBranch: baseBranchName,
150-
HeadRepo: repo,
151-
BaseRepo: repo,
152-
MergeBase: "",
153-
Type: issues_model.PullRequestGitea,
154-
Flow: issues_model.PullRequestFlowAGit,
145+
HeadRepoID: repo.ID,
146+
BaseRepoID: repo.ID,
147+
HeadBranch: headBranch,
148+
BaseBranch: baseBranchName,
149+
HeadRepo: repo,
150+
BaseRepo: repo,
151+
MergeBase: "",
152+
Type: issues_model.PullRequestGitea,
153+
Flow: issues_model.PullRequestFlowAGit,
155154
}
156155
prOpts := &pull_service.NewPullRequestOptions{
157-
Repo: repo,
158-
Issue: prIssue,
159-
PullRequest: pr,
156+
Repo: repo,
157+
Issue: prIssue,
158+
PullRequest: pr,
159+
HeadCommitID: opts.NewCommitIDs[i],
160160
}
161161
if err := pull_service.NewPullRequest(ctx, prOpts); err != nil {
162162
return nil, err
@@ -214,35 +214,29 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
214214
}
215215
}
216216

217-
// Store old commit ID for review staleness checking
218-
oldHeadCommitID := pr.HeadCommitID
219-
220-
pr.HeadCommitID = opts.NewCommitIDs[i]
221-
if err = pull_service.UpdateRef(ctx, pr); err != nil {
217+
if err = pull_service.UpdatePullRequestAgitFlowHead(ctx, pr, opts.NewCommitIDs[i]); err != nil {
222218
return nil, fmt.Errorf("failed to update pull ref. Error: %w", err)
223219
}
224220

225221
// Mark existing reviews as stale when PR content changes (same as regular GitHub flow)
226-
if oldHeadCommitID != opts.NewCommitIDs[i] {
227-
if err := issues_model.MarkReviewsAsStale(ctx, pr.IssueID); err != nil {
228-
log.Error("MarkReviewsAsStale: %v", err)
229-
}
222+
if err := issues_model.MarkReviewsAsStale(ctx, pr.IssueID); err != nil {
223+
log.Error("MarkReviewsAsStale: %v", err)
224+
}
230225

231-
// Dismiss all approval reviews if protected branch rule item enabled
232-
pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
233-
if err != nil {
234-
log.Error("GetFirstMatchProtectedBranchRule: %v", err)
235-
}
236-
if pb != nil && pb.DismissStaleApprovals {
237-
if err := pull_service.DismissApprovalReviews(ctx, pusher, pr); err != nil {
238-
log.Error("DismissApprovalReviews: %v", err)
239-
}
226+
// Dismiss all approval reviews if protected branch rule item enabled
227+
pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
228+
if err != nil {
229+
log.Error("GetFirstMatchProtectedBranchRule: %v", err)
230+
}
231+
if pb != nil && pb.DismissStaleApprovals {
232+
if err := pull_service.DismissApprovalReviews(ctx, pusher, pr); err != nil {
233+
log.Error("DismissApprovalReviews: %v", err)
240234
}
235+
}
241236

242-
// Mark reviews for the new commit as not stale
243-
if err := issues_model.MarkReviewsAsNotStale(ctx, pr.IssueID, opts.NewCommitIDs[i]); err != nil {
244-
log.Error("MarkReviewsAsNotStale: %v", err)
245-
}
237+
// Mark reviews for the new commit as not stale
238+
if err := issues_model.MarkReviewsAsNotStale(ctx, pr.IssueID, opts.NewCommitIDs[i]); err != nil {
239+
log.Error("MarkReviewsAsNotStale: %v", err)
246240
}
247241

248242
pull_service.StartPullRequestCheckImmediately(ctx, pr)

services/pull/patch.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,12 @@ func testPullRequestTmpRepoBranchMergeable(ctx context.Context, prCtx *prTmpRepo
100100
}
101101
}
102102
pr.MergeBase = strings.TrimSpace(pr.MergeBase)
103-
if pr.HeadCommitID, err = gitRepo.GetRefCommitID(git.BranchPrefix + "tracking"); err != nil {
103+
headCommitID, err := gitRepo.GetRefCommitID(git.BranchPrefix + "tracking")
104+
if err != nil {
104105
return fmt.Errorf("GetBranchCommitID: can't find commit ID for head: %w", err)
105106
}
106107

107-
if pr.HeadCommitID == pr.MergeBase {
108+
if headCommitID == pr.MergeBase {
108109
pr.Status = issues_model.PullRequestStatusAncestor
109110
return nil
110111
}

services/pull/pull.go

Lines changed: 50 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func getPullWorkingLockKey(prID int64) string {
4343
type NewPullRequestOptions struct {
4444
Repo *repo_model.Repository
4545
Issue *issues_model.Issue
46+
HeadCommitID string
4647
LabelIDs []int64
4748
AttachmentUUIDs []string
4849
PullRequest *issues_model.PullRequest
@@ -53,6 +54,10 @@ type NewPullRequestOptions struct {
5354

5455
// NewPullRequest creates new pull request with labels for repository.
5556
func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error {
57+
if opts.PullRequest.Flow == issues_model.PullRequestFlowAGit && opts.HeadCommitID == "" {
58+
return errors.New("head commit ID cannot be empty for agit flow")
59+
}
60+
5661
repo, issue, labelIDs, uuids, pr, assigneeIDs := opts.Repo, opts.Issue, opts.LabelIDs, opts.AttachmentUUIDs, opts.PullRequest, opts.AssigneeIDs
5762
if err := issue.LoadPoster(ctx); err != nil {
5863
return err
@@ -98,13 +103,6 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error {
98103
return err
99104
}
100105

101-
divergence, err := git.GetDivergingCommits(ctx, prCtx.tmpBasePath, baseBranch, trackingBranch)
102-
if err != nil {
103-
return err
104-
}
105-
pr.CommitsAhead = divergence.Ahead
106-
pr.CommitsBehind = divergence.Behind
107-
108106
assigneeCommentMap := make(map[int64]*issues_model.Comment)
109107

110108
// add first push codes comment
@@ -131,15 +129,27 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error {
131129
pr.Issue = issue
132130
issue.PullRequest = pr
133131

134-
if pr.Flow == issues_model.PullRequestFlowGithub {
135-
err = PushToBaseRepo(ctx, pr)
132+
// update head commit id into git repository
133+
if pr.Flow == issues_model.PullRequestFlowAGit {
134+
err = UpdatePullRequestAgitFlowHead(ctx, pr, opts.HeadCommitID)
136135
} else {
137-
err = UpdateRef(ctx, pr)
136+
err = UpdatePullRequestGithubFlowHead(ctx, pr)
138137
}
139138
if err != nil {
140139
return err
141140
}
142141

142+
// update commits ahead and behind
143+
divergence, err := git.GetDivergingCommits(ctx, pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitHeadRefName())
144+
if err != nil {
145+
return err
146+
}
147+
pr.CommitsAhead = divergence.Ahead
148+
pr.CommitsBehind = divergence.Behind
149+
if _, err := db.GetEngine(ctx).ID(pr.ID).Cols("commits_ahead", "commits_behind").NoAutoTime().Update(pr); err != nil {
150+
return err
151+
}
152+
143153
if _, err := CreatePushPullComment(ctx, issue.Poster, pr, git.BranchPrefix+pr.BaseBranch, pr.GetGitHeadRefName(), false); err != nil {
144154
return err
145155
}
@@ -388,7 +398,7 @@ func AddTestPullRequestTask(opts TestPullRequestOptions) {
388398
for _, pr := range prs {
389399
log.Trace("Updating PR[%d]: composing new test task", pr.ID)
390400
if pr.Flow == issues_model.PullRequestFlowGithub {
391-
if err := PushToBaseRepo(ctx, pr); err != nil {
401+
if err := UpdatePullRequestGithubFlowHead(ctx, pr); err != nil {
392402
log.Error("PushToBaseRepo: %v", err)
393403
continue
394404
}
@@ -546,68 +556,6 @@ func checkIfPRContentChanged(ctx context.Context, pr *issues_model.PullRequest,
546556
return false, nil
547557
}
548558

549-
// PushToBaseRepo pushes commits from branches of head repository to
550-
// corresponding branches of base repository.
551-
// FIXME: Only push branches that are actually updates?
552-
func PushToBaseRepo(ctx context.Context, pr *issues_model.PullRequest) (err error) {
553-
return pushToBaseRepoHelper(ctx, pr, "")
554-
}
555-
556-
func pushToBaseRepoHelper(ctx context.Context, pr *issues_model.PullRequest, prefixHeadBranch string) (err error) {
557-
log.Trace("PushToBaseRepo[%d]: pushing commits to base repo '%s'", pr.BaseRepoID, pr.GetGitHeadRefName())
558-
559-
if err := pr.LoadHeadRepo(ctx); err != nil {
560-
log.Error("Unable to load head repository for PR[%d] Error: %v", pr.ID, err)
561-
return err
562-
}
563-
headRepoPath := pr.HeadRepo.RepoPath()
564-
565-
if err := pr.LoadBaseRepo(ctx); err != nil {
566-
log.Error("Unable to load base repository for PR[%d] Error: %v", pr.ID, err)
567-
return err
568-
}
569-
baseRepoPath := pr.BaseRepo.RepoPath()
570-
571-
if err = pr.LoadIssue(ctx); err != nil {
572-
return fmt.Errorf("unable to load issue %d for pr %d: %w", pr.IssueID, pr.ID, err)
573-
}
574-
if err = pr.Issue.LoadPoster(ctx); err != nil {
575-
return fmt.Errorf("unable to load poster %d for pr %d: %w", pr.Issue.PosterID, pr.ID, err)
576-
}
577-
578-
gitRefName := pr.GetGitHeadRefName()
579-
580-
if err := git.Push(ctx, headRepoPath, git.PushOptions{
581-
Remote: baseRepoPath,
582-
Branch: prefixHeadBranch + pr.HeadBranch + ":" + gitRefName,
583-
Force: true,
584-
// Use InternalPushingEnvironment here because we know that pre-receive and post-receive do not run on a refs/pulls/...
585-
Env: repo_module.InternalPushingEnvironment(pr.Issue.Poster, pr.BaseRepo),
586-
}); err != nil {
587-
if git.IsErrPushOutOfDate(err) {
588-
// This should not happen as we're using force!
589-
log.Error("Unable to push PR head for %s#%d (%-v:%s) due to ErrPushOfDate: %v", pr.BaseRepo.FullName(), pr.Index, pr.BaseRepo, gitRefName, err)
590-
return err
591-
} else if git.IsErrPushRejected(err) {
592-
rejectErr := err.(*git.ErrPushRejected)
593-
log.Info("Unable to push PR head for %s#%d (%-v:%s) due to rejection:\nStdout: %s\nStderr: %s\nError: %v", pr.BaseRepo.FullName(), pr.Index, pr.BaseRepo, gitRefName, rejectErr.StdOut, rejectErr.StdErr, rejectErr.Err)
594-
return err
595-
} else if git.IsErrMoreThanOne(err) {
596-
if prefixHeadBranch != "" {
597-
log.Info("Can't push with %s%s", prefixHeadBranch, pr.HeadBranch)
598-
return err
599-
}
600-
log.Info("Retrying to push with %s%s", git.BranchPrefix, pr.HeadBranch)
601-
err = pushToBaseRepoHelper(ctx, pr, git.BranchPrefix)
602-
return err
603-
}
604-
log.Error("Unable to push PR head for %s#%d (%-v:%s) due to Error: %v", pr.BaseRepo.FullName(), pr.Index, pr.BaseRepo, gitRefName, err)
605-
return fmt.Errorf("Push: %s:%s %s:%s %w", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), gitRefName, err)
606-
}
607-
608-
return nil
609-
}
610-
611559
// UpdatePullsRefs update all the PRs head file pointers like /refs/pull/1/head so that it will be dependent by other operations
612560
func UpdatePullsRefs(ctx context.Context, repo *repo_model.Repository, update *repo_module.PushUpdateOptions) {
613561
branch := update.RefFullName.BranchName()
@@ -619,27 +567,43 @@ func UpdatePullsRefs(ctx context.Context, repo *repo_model.Repository, update *r
619567
for _, pr := range prs {
620568
log.Trace("Updating PR[%d]: composing new test task", pr.ID)
621569
if pr.Flow == issues_model.PullRequestFlowGithub {
622-
if err := PushToBaseRepo(ctx, pr); err != nil {
623-
log.Error("PushToBaseRepo: %v", err)
570+
if err := UpdatePullRequestGithubFlowHead(ctx, pr); err != nil {
571+
log.Error("UpdatePullRequestHead: %v", err)
624572
}
625573
}
626574
}
627575
}
628576
}
629577

630-
// UpdateRef update refs/pull/id/head directly for agit flow pull request
631-
func UpdateRef(ctx context.Context, pr *issues_model.PullRequest) (err error) {
632-
log.Trace("UpdateRef[%d]: upgate pull request ref in base repo '%s'", pr.ID, pr.GetGitHeadRefName())
578+
func UpdatePullRequestAgitFlowHead(ctx context.Context, pr *issues_model.PullRequest, commitID string) error {
579+
log.Trace("UpdateAgitPullRequestHead[%d]: update pull request head in base repo '%s'", pr.ID, pr.GetGitHeadRefName())
580+
581+
_, _, err := git.NewCommand("update-ref").AddDynamicArguments(pr.GetGitHeadRefName(), commitID).RunStdString(ctx, &git.RunOpts{Dir: pr.BaseRepo.RepoPath()})
582+
return err
583+
}
584+
585+
// UpdatePullRequestHeadRef updates the head reference of a pull request
586+
func UpdatePullRequestGithubFlowHead(ctx context.Context, pr *issues_model.PullRequest) error {
587+
log.Trace("UpdatePullRequestHeadRef[%d]: update pull request ref in base repo '%s'", pr.ID, pr.GetGitHeadRefName())
588+
633589
if err := pr.LoadBaseRepo(ctx); err != nil {
634-
log.Error("Unable to load base repository for PR[%d] Error: %v", pr.ID, err)
635590
return err
636591
}
637592

638-
_, _, err = git.NewCommand("update-ref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.HeadCommitID).RunStdString(ctx, &git.RunOpts{Dir: pr.BaseRepo.RepoPath()})
639-
if err != nil {
640-
log.Error("Unable to update ref in base repository for PR[%d] Error: %v", pr.ID, err)
593+
if pr.IsSameRepo() { // for agit flow or github flow in the same repository
594+
_, _, err := git.NewCommand("update-ref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.HeadBranch).RunStdString(ctx, &git.RunOpts{Dir: pr.BaseRepo.RepoPath()})
595+
return err
596+
}
597+
598+
// for cross repository pull request
599+
if err := pr.LoadHeadRepo(ctx); err != nil {
600+
return err
641601
}
642602

603+
_, _, err := git.NewCommand("fetch", "--no-tags", "--refmap=").
604+
AddDynamicArguments(pr.HeadRepo.RepoPath()).
605+
AddDynamicArguments(fmt.Sprintf("refs/heads/%s:%s", pr.HeadBranch, pr.GetGitHeadRefName())).
606+
RunStdString(ctx, &git.RunOpts{Dir: pr.BaseRepo.RepoPath()})
643607
return err
644608
}
645609

@@ -803,12 +767,12 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ
803767
if pr.Flow == issues_model.PullRequestFlowGithub {
804768
headCommit, err = gitRepo.GetBranchCommit(pr.HeadBranch)
805769
} else {
806-
pr.HeadCommitID, err = gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
770+
headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
807771
if err != nil {
808772
log.Error("Unable to get head commit: %s Error: %v", pr.GetGitHeadRefName(), err)
809773
return ""
810774
}
811-
headCommit, err = gitRepo.GetCommit(pr.HeadCommitID)
775+
headCommit, err = gitRepo.GetCommit(headCommitID)
812776
}
813777
if err != nil {
814778
log.Error("Unable to get head commit: %s Error: %v", pr.HeadBranch, err)
@@ -1030,11 +994,11 @@ func IsHeadEqualWithBranch(ctx context.Context, pr *issues_model.PullRequest, br
1030994
return false, err
1031995
}
1032996
} else {
1033-
pr.HeadCommitID, err = baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
997+
headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
1034998
if err != nil {
1035999
return false, err
10361000
}
1037-
if headCommit, err = baseGitRepo.GetCommit(pr.HeadCommitID); err != nil {
1001+
if headCommit, err = baseGitRepo.GetCommit(headCommitID); err != nil {
10381002
return false, err
10391003
}
10401004
}

services/pull/temp_repo.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,10 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest)
166166
}
167167

168168
trackingBranch := "tracking"
169-
objectFormat := git.ObjectFormatFromName(pr.BaseRepo.ObjectFormatName)
170169
// Fetch head branch
171170
var headBranch string
172171
if pr.Flow == issues_model.PullRequestFlowGithub {
173172
headBranch = git.BranchPrefix + pr.HeadBranch
174-
} else if len(pr.HeadCommitID) == objectFormat.FullLength() { // for not created pull request
175-
headBranch = pr.HeadCommitID
176173
} else {
177174
headBranch = pr.GetGitHeadRefName()
178175
}

tests/integration/git_misc_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ func TestAgitReviewStaleness(t *testing.T) {
170170
assert.NoError(t, pr.LoadIssue(t.Context()))
171171

172172
// Get initial commit ID for the review
173-
initialCommitID := pr.HeadCommitID
173+
initialCommitID, err := gitRepo.GetRefCommitID(pr.GetGitHeadRefName())
174+
assert.NoError(t, err)
174175
t.Logf("Initial commit ID: %s", initialCommitID)
175176

176177
// Create a review on the PR (as user1 reviewing user2's PR)

0 commit comments

Comments
 (0)