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>
This commit is contained in:
zeripath 2021-12-20 00:32:54 +00:00 committed by GitHub
parent b24a965b81
commit e4e411821d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 42 additions and 9 deletions

View file

@ -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