1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-03 09:07:19 +00:00

Move checks for pulls before merge into own function (#19271)

This make checks in one single place so they dont differ and maintainer can not forget a check in one place while adding it to the other .... ( as it's atm )

Fix:
* The API does ignore issue dependencies where Web does not
* The API checks if "IsSignedIfRequired" where Web does not - UI probably do but nothing will some to craft custom requests
* Default merge message is crafted a bit different between API and Web if not set on specific cases ...
This commit is contained in:
6543
2022-03-31 16:53:08 +02:00
committed by GitHub
parent f6145a69c4
commit 9c349a4277
9 changed files with 217 additions and 211 deletions

View File

@ -7,6 +7,7 @@ package pull
import (
"context"
"errors"
"fmt"
"os"
"strconv"
@ -24,11 +25,21 @@ import (
"code.gitea.io/gitea/modules/queue"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
asymkey_service "code.gitea.io/gitea/services/asymkey"
)
// prQueue represents a queue to handle update pull request tests
var prQueue queue.UniqueQueue
var (
ErrIsClosed = errors.New("pull is cosed")
ErrUserNotAllowedToMerge = errors.New("user not allowed to merge")
ErrHasMerged = errors.New("has already been merged")
ErrIsWorkInProgress = errors.New("work in progress PRs cannot be merged")
ErrNotMergableState = errors.New("not in mergeable state")
ErrDependenciesLeft = errors.New("is blocked by an open dependency")
)
// AddToTaskQueue adds itself to pull request test task queue.
func AddToTaskQueue(pr *models.PullRequest) {
err := prQueue.PushFunc(strconv.FormatInt(pr.ID, 10), func() error {
@ -46,6 +57,79 @@ func AddToTaskQueue(pr *models.PullRequest) {
}
}
// CheckPullMergable check if the pull mergable based on all conditions (branch protection, merge options, ...)
func CheckPullMergable(ctx context.Context, doer *user_model.User, perm *models.Permission, pr *models.PullRequest, manuallMerge, force bool) error {
if pr.HasMerged {
return ErrHasMerged
}
if err := pr.LoadIssue(); err != nil {
return err
} else if pr.Issue.IsClosed {
return ErrIsClosed
}
if allowedMerge, err := IsUserAllowedToMerge(pr, *perm, doer); err != nil {
return err
} else if !allowedMerge {
return ErrUserNotAllowedToMerge
}
if manuallMerge {
// don't check rules to "auto merge", doer is going to mark this pull as merged manually
return nil
}
if pr.IsWorkInProgress() {
return ErrIsWorkInProgress
}
if !pr.CanAutoMerge() {
return ErrNotMergableState
}
if err := CheckPRReadyToMerge(ctx, pr, false); err != nil {
if models.IsErrDisallowedToMerge(err) {
if force {
if isRepoAdmin, err := models.IsUserRepoAdmin(pr.BaseRepo, doer); err != nil {
return err
} else if !isRepoAdmin {
return ErrUserNotAllowedToMerge
}
}
} else {
return err
}
}
if _, err := isSignedIfRequired(ctx, pr, doer); err != nil {
return err
}
if noDeps, err := models.IssueNoDependenciesLeft(pr.Issue); err != nil {
return err
} else if !noDeps {
return ErrDependenciesLeft
}
return nil
}
// isSignedIfRequired check if merge will be signed if required
func isSignedIfRequired(ctx context.Context, pr *models.PullRequest, doer *user_model.User) (bool, error) {
if err := pr.LoadProtectedBranch(); err != nil {
return false, err
}
if pr.ProtectedBranch == nil || !pr.ProtectedBranch.RequireSignedCommits {
return true, nil
}
sign, _, _, err := asymkey_service.SignMerge(ctx, pr, doer, pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName())
return sign, err
}
// checkAndUpdateStatus checks if pull request is possible to leaving checking status,
// and set to be either conflict or mergeable.
func checkAndUpdateStatus(pr *models.PullRequest) {