summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2021-12-20 00:32:54 +0000
committerGitHub <noreply@github.com>2021-12-20 08:32:54 +0800
commite4e411821d985cf8f9007d9640909ab9ee271dd7 (patch)
tree11af3c3a933949d0561f1e292acd8296181a63db /services
parentb24a965b81d5aa4e7bd87c6a4c6370d7e0ec9a50 (diff)
downloadgitea-e4e411821d985cf8f9007d9640909ab9ee271dd7.tar.gz
gitea-e4e411821d985cf8f9007d9640909ab9ee271dd7.zip
Abort merge if head has been updated before pressing merge (#18032)
* Abort merge if head has been updated before pressing merge It is possible that a PR head may be pushed to between the merge page being shown and the merge button being pressed. Pass the current expected head in as a parameter and cancel the merge if it has changed. Fix #18028 Signed-off-by: Andrew Thornton <art27@cantab.net> * adjust swagger Signed-off-by: Andrew Thornton <art27@cantab.net> * fix test Signed-off-by: Andrew Thornton <art27@cantab.net> * placate lint Signed-off-by: Andrew Thornton <art27@cantab.net>
Diffstat (limited to 'services')
-rw-r--r--services/forms/repo_form.go1
-rw-r--r--services/pull/merge.go20
-rw-r--r--services/pull/update.go2
3 files changed, 19 insertions, 4 deletions
diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go
index c571951bb9..19b5a37664 100644
--- a/services/forms/repo_form.go
+++ b/services/forms/repo_form.go
@@ -571,6 +571,7 @@ type MergePullRequestForm struct {
MergeTitleField string
MergeMessageField string
MergeCommitID string // only used for manually-merged
+ HeadCommitID string `json:"head_commit_id,omitempty"`
ForceMerge *bool `json:"force_merge,omitempty"`
DeleteBranchAfterMerge bool `json:"delete_branch_after_merge,omitempty"`
}
diff --git a/services/pull/merge.go b/services/pull/merge.go
index ab1f43a50a..e541495bef 100644
--- a/services/pull/merge.go
+++ b/services/pull/merge.go
@@ -34,7 +34,7 @@ import (
// Merge merges pull request to base repository.
// Caller should check PR is ready to be merged (review and status checks)
// FIXME: add repoWorkingPull make sure two merges does not happen at same time.
-func Merge(pr *models.PullRequest, doer *user_model.User, baseGitRepo *git.Repository, mergeStyle repo_model.MergeStyle, message string) (err error) {
+func Merge(pr *models.PullRequest, doer *user_model.User, baseGitRepo *git.Repository, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string) (err error) {
if err = pr.LoadHeadRepo(); err != nil {
log.Error("LoadHeadRepo: %v", err)
return fmt.Errorf("LoadHeadRepo: %v", err)
@@ -59,7 +59,7 @@ func Merge(pr *models.PullRequest, doer *user_model.User, baseGitRepo *git.Repos
go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false, "", "")
}()
- pr.MergedCommitID, err = rawMerge(pr, doer, mergeStyle, message)
+ pr.MergedCommitID, err = rawMerge(pr, doer, mergeStyle, expectedHeadCommitID, message)
if err != nil {
return err
}
@@ -114,7 +114,7 @@ func Merge(pr *models.PullRequest, doer *user_model.User, baseGitRepo *git.Repos
}
// rawMerge perform the merge operation without changing any pull information in database
-func rawMerge(pr *models.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle, message string) (string, error) {
+func rawMerge(pr *models.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string) (string, error) {
err := git.LoadGitVersion()
if err != nil {
log.Error("git.LoadGitVersion: %v", err)
@@ -137,6 +137,20 @@ func rawMerge(pr *models.PullRequest, doer *user_model.User, mergeStyle repo_mod
trackingBranch := "tracking"
stagingBranch := "staging"
+ if expectedHeadCommitID != "" {
+ trackingCommitID, err := git.NewCommand("show-ref", "--hash", git.BranchPrefix+trackingBranch).RunInDir(tmpBasePath)
+ if err != nil {
+ log.Error("show-ref[%s] --hash refs/heads/trackingn: %v", tmpBasePath, git.BranchPrefix+trackingBranch, err)
+ return "", fmt.Errorf("getDiffTree: %v", err)
+ }
+ if strings.TrimSpace(trackingCommitID) != expectedHeadCommitID {
+ return "", models.ErrSHADoesNotMatch{
+ GivenSHA: expectedHeadCommitID,
+ CurrentSHA: trackingCommitID,
+ }
+ }
+ }
+
var outbuf, errbuf strings.Builder
// Enable sparse-checkout
diff --git a/services/pull/update.go b/services/pull/update.go
index 25c6d36308..8ca7e4cee7 100644
--- a/services/pull/update.go
+++ b/services/pull/update.go
@@ -55,7 +55,7 @@ func Update(pull *models.PullRequest, doer *user_model.User, message string, reb
return fmt.Errorf("HeadBranch of PR %d is up to date", pull.Index)
}
- _, err = rawMerge(pr, doer, style, message)
+ _, err = rawMerge(pr, doer, style, "", message)
defer func() {
if rebase {