aboutsummaryrefslogtreecommitdiffstats
path: root/routers
diff options
context:
space:
mode:
Diffstat (limited to 'routers')
-rw-r--r--routers/api/v1/repo/pull.go103
-rw-r--r--routers/private/hook_pre_receive.go2
-rw-r--r--routers/web/repo/pull.go132
3 files changed, 73 insertions, 164 deletions
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index 65544b80b3..bb922ddb23 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -723,13 +723,12 @@ func MergePullRequest(ctx *context.APIContext) {
return
}
- if err = pr.LoadHeadRepo(); err != nil {
+ if err := pr.LoadHeadRepo(); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err)
return
}
- err = pr.LoadIssue()
- if err != nil {
+ if err := pr.LoadIssue(); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
return
}
@@ -743,29 +742,33 @@ func MergePullRequest(ctx *context.APIContext) {
}
}
- if pr.Issue.IsClosed {
- ctx.NotFound()
- return
- }
+ manuallMerge := repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged
+ force := form.ForceMerge != nil && *form.ForceMerge
- allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.Repo.Permission, ctx.Doer)
- if err != nil {
- ctx.Error(http.StatusInternalServerError, "IsUSerAllowedToMerge", err)
- return
- }
- if !allowedMerge {
- ctx.Error(http.StatusMethodNotAllowed, "Merge", "User not allowed to merge PR")
- return
- }
-
- if pr.HasMerged {
- ctx.Error(http.StatusMethodNotAllowed, "PR already merged", "")
+ if err := pull_service.CheckPullMergable(ctx, ctx.Doer, &ctx.Repo.Permission, pr, manuallMerge, force); err != nil {
+ if errors.Is(err, pull_service.ErrIsClosed) {
+ ctx.NotFound()
+ } else if errors.Is(err, pull_service.ErrUserNotAllowedToMerge) {
+ ctx.Error(http.StatusMethodNotAllowed, "Merge", "User not allowed to merge PR")
+ } else if errors.Is(err, pull_service.ErrHasMerged) {
+ ctx.Error(http.StatusMethodNotAllowed, "PR already merged", "")
+ } else if errors.Is(err, pull_service.ErrIsWorkInProgress) {
+ ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged")
+ } else if errors.Is(err, pull_service.ErrNotMergableState) {
+ ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later")
+ } else if models.IsErrDisallowedToMerge(err) {
+ ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err)
+ } else if asymkey_service.IsErrWontSign(err) {
+ ctx.Error(http.StatusMethodNotAllowed, fmt.Sprintf("Protected branch %s requires signed commits but this merge would not be signed", pr.BaseBranch), err)
+ } else {
+ ctx.InternalServerError(err)
+ }
return
}
// handle manually-merged mark
- if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged {
- if err = pull_service.MergedManually(pr, ctx.Doer, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
+ if manuallMerge {
+ if err := pull_service.MergedManually(pr, ctx.Doer, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
if models.IsErrInvalidMergeStyle(err) {
ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do)))
return
@@ -781,63 +784,13 @@ func MergePullRequest(ctx *context.APIContext) {
return
}
- if !pr.CanAutoMerge() {
- ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later")
+ // set defaults to propagate needed fields
+ if err := form.SetDefaults(pr); err != nil {
+ ctx.ServerError("SetDefaults", fmt.Errorf("SetDefaults: %v", err))
return
}
- if pr.IsWorkInProgress() {
- ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged")
- return
- }
-
- if err := pull_service.CheckPRReadyToMerge(ctx, pr, false); err != nil {
- if !models.IsErrNotAllowedToMerge(err) {
- ctx.Error(http.StatusInternalServerError, "CheckPRReadyToMerge", err)
- return
- }
- if form.ForceMerge != nil && *form.ForceMerge {
- if isRepoAdmin, err := models.IsUserRepoAdmin(pr.BaseRepo, ctx.Doer); err != nil {
- ctx.Error(http.StatusInternalServerError, "IsUserRepoAdmin", err)
- return
- } else if !isRepoAdmin {
- ctx.Error(http.StatusMethodNotAllowed, "Merge", "Only repository admin can merge if not all checks are ok (force merge)")
- }
- } else {
- ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err)
- return
- }
- }
-
- if _, err := pull_service.IsSignedIfRequired(ctx, pr, ctx.Doer); err != nil {
- if !asymkey_service.IsErrWontSign(err) {
- ctx.Error(http.StatusInternalServerError, "IsSignedIfRequired", err)
- return
- }
- ctx.Error(http.StatusMethodNotAllowed, fmt.Sprintf("Protected branch %s requires signed commits but this merge would not be signed", pr.BaseBranch), err)
- return
- }
-
- if len(form.Do) == 0 {
- form.Do = string(repo_model.MergeStyleMerge)
- }
-
- message := strings.TrimSpace(form.MergeTitleField)
- if len(message) == 0 {
- if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleMerge {
- message = pr.GetDefaultMergeMessage()
- }
- if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleSquash {
- message = pr.GetDefaultSquashMessage()
- }
- }
-
- form.MergeMessageField = strings.TrimSpace(form.MergeMessageField)
- if len(form.MergeMessageField) > 0 {
- message += "\n\n" + form.MergeMessageField
- }
-
- if err := pull_service.Merge(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message); err != nil {
+ if err := pull_service.Merge(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, form.MergeTitleField); err != nil {
if models.IsErrInvalidMergeStyle(err) {
ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do)))
return
diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go
index c6ea422287..f3f876edca 100644
--- a/routers/private/hook_pre_receive.go
+++ b/routers/private/hook_pre_receive.go
@@ -340,7 +340,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
// Check all status checks and reviews are ok
if err := pull_service.CheckPRReadyToMerge(ctx, pr, true); err != nil {
- if models.IsErrNotAllowedToMerge(err) {
+ if models.IsErrDisallowedToMerge(err) {
log.Warn("Forbidden: User %d is not allowed push to protected branch %s in %-v and pr #%d is not ready to be merged: %s", ctx.opts.UserID, branchName, repo, pr.Index, err.Error())
ctx.JSON(http.StatusForbidden, private.Response{
Err: fmt.Sprintf("Not allowed to push to protected branch %s and pr #%d is not ready to be merged: %s", branchName, ctx.opts.PullRequestID, err.Error()),
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index 7b24e5dabb..32d9a65cbd 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -34,6 +34,7 @@ import (
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/routers/utils"
+ asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/forms"
"code.gitea.io/gitea/services/gitdiff"
pull_service "code.gitea.io/gitea/services/pull"
@@ -858,39 +859,53 @@ func MergePullRequest(ctx *context.Context) {
if ctx.Written() {
return
}
- if issue.IsClosed {
- if issue.IsPull {
- ctx.Flash.Error(ctx.Tr("repo.pulls.is_closed"))
- ctx.Redirect(issue.Link())
- return
- }
- ctx.Flash.Error(ctx.Tr("repo.issues.closed_title"))
- ctx.Redirect(issue.Link())
- return
- }
pr := issue.PullRequest
+ pr.Issue = issue
+ pr.Issue.Repo = ctx.Repo.Repository
+ manuallMerge := repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged
+ forceMerge := form.ForceMerge != nil && *form.ForceMerge
- allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.Repo.Permission, ctx.Doer)
- if err != nil {
- ctx.ServerError("IsUserAllowedToMerge", err)
- return
- }
- if !allowedMerge {
- ctx.Flash.Error(ctx.Tr("repo.pulls.update_not_allowed"))
- ctx.Redirect(issue.Link())
- return
- }
+ if err := pull_service.CheckPullMergable(ctx, ctx.Doer, &ctx.Repo.Permission, pr, manuallMerge, forceMerge); err != nil {
+ if errors.Is(err, pull_service.ErrIsClosed) {
+ if issue.IsPull {
+ ctx.Flash.Error(ctx.Tr("repo.pulls.is_closed"))
+ ctx.Redirect(issue.Link())
+ } else {
+ ctx.Flash.Error(ctx.Tr("repo.issues.closed_title"))
+ ctx.Redirect(issue.Link())
+ }
+ } else if errors.Is(err, pull_service.ErrUserNotAllowedToMerge) {
+ ctx.Flash.Error(ctx.Tr("repo.pulls.update_not_allowed"))
+ ctx.Redirect(issue.Link())
+ } else if errors.Is(err, pull_service.ErrHasMerged) {
+ ctx.Flash.Error(ctx.Tr("repo.pulls.has_merged"))
+ ctx.Redirect(issue.Link())
+ } else if errors.Is(err, pull_service.ErrIsWorkInProgress) {
+ ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_wip"))
+ ctx.Redirect(issue.Link())
+ } else if errors.Is(err, pull_service.ErrNotMergableState) {
+ ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
+ ctx.Redirect(issue.Link())
+ } else if models.IsErrDisallowedToMerge(err) {
+ ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
+ ctx.Redirect(issue.Link())
+ } else if asymkey_service.IsErrWontSign(err) {
+ ctx.Flash.Error(err.Error()) // has not translation ...
+ ctx.Redirect(issue.Link())
+ } else if errors.Is(err, pull_service.ErrDependenciesLeft) {
+ ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
+ ctx.Redirect(issue.Link())
+ } else {
+ ctx.ServerError("WebCheck", err)
+ }
- if pr.HasMerged {
- ctx.Flash.Error(ctx.Tr("repo.pulls.has_merged"))
- ctx.Redirect(issue.Link())
return
}
// handle manually-merged mark
- if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged {
- if err = pull_service.MergedManually(pr, ctx.Doer, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
+ if manuallMerge {
+ if err := pull_service.MergedManually(pr, ctx.Doer, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
if models.IsErrInvalidMergeStyle(err) {
ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
ctx.Redirect(issue.Link())
@@ -909,72 +924,13 @@ func MergePullRequest(ctx *context.Context) {
return
}
- if !pr.CanAutoMerge() {
- ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
- ctx.Redirect(issue.Link())
- return
- }
-
- if pr.IsWorkInProgress() {
- ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_wip"))
- ctx.Redirect(issue.Link())
- return
- }
-
- if err := pull_service.CheckPRReadyToMerge(ctx, pr, false); err != nil {
- if !models.IsErrNotAllowedToMerge(err) {
- ctx.ServerError("Merge PR status", err)
- return
- }
- if isRepoAdmin, err := models.IsUserRepoAdmin(pr.BaseRepo, ctx.Doer); err != nil {
- ctx.ServerError("IsUserRepoAdmin", err)
- return
- } else if !isRepoAdmin {
- ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
- ctx.Redirect(issue.Link())
- return
- }
- }
-
- if ctx.HasError() {
- ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
- ctx.Redirect(issue.Link())
- return
- }
-
- message := strings.TrimSpace(form.MergeTitleField)
- if len(message) == 0 {
- if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleMerge {
- message = pr.GetDefaultMergeMessage()
- }
- if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleRebaseMerge {
- message = pr.GetDefaultMergeMessage()
- }
- if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleSquash {
- message = pr.GetDefaultSquashMessage()
- }
- }
-
- form.MergeMessageField = strings.TrimSpace(form.MergeMessageField)
- if len(form.MergeMessageField) > 0 {
- message += "\n\n" + form.MergeMessageField
- }
-
- pr.Issue = issue
- pr.Issue.Repo = ctx.Repo.Repository
-
- noDeps, err := models.IssueNoDependenciesLeft(issue)
- if err != nil {
- return
- }
-
- if !noDeps {
- ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
- ctx.Redirect(issue.Link())
+ // set defaults to propagate needed fields
+ if err := form.SetDefaults(pr); err != nil {
+ ctx.ServerError("SetDefaults", fmt.Errorf("SetDefaults: %v", err))
return
}
- if err = pull_service.Merge(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message); err != nil {
+ if err := pull_service.Merge(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, form.MergeTitleField); err != nil {
if models.IsErrInvalidMergeStyle(err) {
ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
ctx.Redirect(issue.Link())