summaryrefslogtreecommitdiffstats
path: root/services/pull/merge.go
diff options
context:
space:
mode:
authorDavid Svantesson <davidsvantesson@gmail.com>2020-01-11 08:29:34 +0100
committertechknowlogick <techknowlogick@gitea.io>2020-01-11 02:29:34 -0500
commit32fb813133c74ddc3af1964e81fff72fea4f24f1 (patch)
tree31eec446f12e448d7cf398db43620606e9704ff1 /services/pull/merge.go
parent4d06d10dbafe7cfd404889b636d8e243058ee96f (diff)
downloadgitea-32fb813133c74ddc3af1964e81fff72fea4f24f1.tar.gz
gitea-32fb813133c74ddc3af1964e81fff72fea4f24f1.zip
Allow repo admin to merge PR regardless of review status (#9611)
* Allow repo admin to merge even if review is not ok.
Diffstat (limited to 'services/pull/merge.go')
-rw-r--r--services/pull/merge.go67
1 files changed, 62 insertions, 5 deletions
diff --git a/services/pull/merge.go b/services/pull/merge.go
index 7aec7cef3e..e825c3fdd1 100644
--- a/services/pull/merge.go
+++ b/services/pull/merge.go
@@ -30,6 +30,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 *models.User, baseGitRepo *git.Repository, mergeStyle models.MergeStyle, message string) (err error) {
binVersion, err := git.BinVersion()
@@ -53,11 +54,6 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
}
prConfig := prUnit.PullRequestsConfig()
- if err := pr.CheckUserAllowedToMerge(doer); err != nil {
- log.Error("CheckUserAllowedToMerge(%v): %v", doer, err)
- return fmt.Errorf("CheckUserAllowedToMerge: %v", err)
- }
-
// Check if merge style is correct and allowed
if !prConfig.IsMergeStyleAllowed(mergeStyle) {
return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: mergeStyle}
@@ -473,3 +469,64 @@ func getDiffTree(repoPath, baseBranch, headBranch string) (string, error) {
return out.String(), nil
}
+
+// IsUserAllowedToMerge check if user is allowed to merge PR with given permissions and branch protections
+func IsUserAllowedToMerge(pr *models.PullRequest, p models.Permission, user *models.User) (bool, error) {
+ if p.IsAdmin() {
+ return true, nil
+ }
+ if !p.CanWrite(models.UnitTypeCode) {
+ return false, nil
+ }
+
+ err := pr.LoadProtectedBranch()
+ if err != nil {
+ return false, err
+ }
+
+ if pr.ProtectedBranch == nil || pr.ProtectedBranch.IsUserMergeWhitelisted(user.ID) {
+ return true, nil
+ }
+
+ return false, nil
+}
+
+// CheckPRReadyToMerge checks whether the PR is ready to be merged (reviews and status checks)
+func CheckPRReadyToMerge(pr *models.PullRequest) (err error) {
+ if pr.BaseRepo == nil {
+ if err = pr.GetBaseRepo(); err != nil {
+ return fmt.Errorf("GetBaseRepo: %v", err)
+ }
+ }
+ if pr.ProtectedBranch == nil {
+ if err = pr.LoadProtectedBranch(); err != nil {
+ return fmt.Errorf("LoadProtectedBranch: %v", err)
+ }
+ if pr.ProtectedBranch == nil {
+ return nil
+ }
+ }
+
+ isPass, err := IsPullCommitStatusPass(pr)
+ if err != nil {
+ return err
+ }
+ if !isPass {
+ return models.ErrNotAllowedToMerge{
+ Reason: "Not all required status checks successful",
+ }
+ }
+
+ if enoughApprovals := pr.ProtectedBranch.HasEnoughApprovals(pr); !enoughApprovals {
+ return models.ErrNotAllowedToMerge{
+ Reason: "Does not have enough approvals",
+ }
+ }
+ if rejected := pr.ProtectedBranch.MergeBlockedByRejectedReview(pr); rejected {
+ return models.ErrNotAllowedToMerge{
+ Reason: "There are requested changes",
+ }
+ }
+
+ return nil
+}