mirror of
https://github.com/go-gitea/gitea
synced 2025-08-10 03:28:20 +00:00
Refuse merge until all required status checks success (#7481)
* refuse merge until ci successfully * deny merge request when required status checkes not succeed on merge Post and API * add database migration for added columns on protected_branch * fix migration * fix protected branch check bug * fix protected branch settings * remove duplicated code on check pull request's required commit statuses pass * remove unused codes * fix migration * add newline for template file * fix go mod * rename function name and some other fixes * fix template * fix bug pull view * remove go1.12 wrong dependencies * add administrator bypass when protected branch status check enabled * fix bug * improve the codes
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
"code.gitea.io/gitea/modules/pull"
|
||||
pull_service "code.gitea.io/gitea/modules/pull"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
milestone_service "code.gitea.io/gitea/services/milestone"
|
||||
@@ -571,6 +572,17 @@ func MergePullRequest(ctx *context.APIContext, form auth.MergePullRequestForm) {
|
||||
return
|
||||
}
|
||||
|
||||
isPass, err := pull_service.IsPullCommitStatusPass(pr)
|
||||
if err != nil {
|
||||
ctx.Error(500, "IsPullCommitStatusPass", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !isPass && !ctx.IsUserRepoAdmin() {
|
||||
ctx.Status(405)
|
||||
return
|
||||
}
|
||||
|
||||
if len(form.Do) == 0 {
|
||||
form.Do = string(models.MergeStyleMerge)
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
"code.gitea.io/gitea/modules/pull"
|
||||
pull_service "code.gitea.io/gitea/modules/pull"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
@@ -322,6 +323,12 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
|
||||
|
||||
setMergeTarget(ctx, pull)
|
||||
|
||||
if err = pull.LoadProtectedBranch(); err != nil {
|
||||
ctx.ServerError("GetLatestCommitStatus", err)
|
||||
return nil
|
||||
}
|
||||
ctx.Data["EnableStatusCheck"] = pull.ProtectedBranch != nil && pull.ProtectedBranch.EnableStatusCheck
|
||||
|
||||
var headGitRepo *git.Repository
|
||||
var headBranchExist bool
|
||||
// HeadRepo may be missing
|
||||
@@ -350,6 +357,18 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
|
||||
ctx.Data["LatestCommitStatuses"] = commitStatuses
|
||||
ctx.Data["LatestCommitStatus"] = models.CalcCommitStatus(commitStatuses)
|
||||
}
|
||||
|
||||
if pull.ProtectedBranch != nil && pull.ProtectedBranch.EnableStatusCheck {
|
||||
ctx.Data["is_context_required"] = func(context string) bool {
|
||||
for _, c := range pull.ProtectedBranch.StatusCheckContexts {
|
||||
if c == context {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
ctx.Data["IsRequiredStatusCheckSuccess"] = pull_service.IsCommitStatusContextSuccess(commitStatuses, pull.ProtectedBranch.StatusCheckContexts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,6 +627,17 @@ func MergePullRequest(ctx *context.Context, form auth.MergePullRequestForm) {
|
||||
return
|
||||
}
|
||||
|
||||
isPass, err := pull_service.IsPullCommitStatusPass(pr)
|
||||
if err != nil {
|
||||
ctx.ServerError("IsPullCommitStatusPass", err)
|
||||
return
|
||||
}
|
||||
if !isPass && !ctx.IsUserRepoAdmin() {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_status_check"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
|
||||
|
@@ -7,6 +7,7 @@ package repo
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/auth"
|
||||
@@ -125,6 +126,29 @@ func SettingsProtectedBranch(c *context.Context) {
|
||||
c.Data["whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.WhitelistUserIDs), ",")
|
||||
c.Data["merge_whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.MergeWhitelistUserIDs), ",")
|
||||
c.Data["approvals_whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.ApprovalsWhitelistUserIDs), ",")
|
||||
contexts, _ := models.FindRepoRecentCommitStatusContexts(c.Repo.Repository.ID, 7*24*time.Hour) // Find last week status check contexts
|
||||
for _, context := range protectBranch.StatusCheckContexts {
|
||||
var found bool
|
||||
for _, ctx := range contexts {
|
||||
if ctx == context {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
contexts = append(contexts, context)
|
||||
}
|
||||
}
|
||||
|
||||
c.Data["branch_status_check_contexts"] = contexts
|
||||
c.Data["is_context_required"] = func(context string) bool {
|
||||
for _, c := range protectBranch.StatusCheckContexts {
|
||||
if c == context {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if c.Repo.Owner.IsOrganization() {
|
||||
teams, err := c.Repo.Owner.TeamsWithAccessToRepo(c.Repo.Repository.ID, models.AccessModeRead)
|
||||
@@ -186,6 +210,10 @@ func SettingsProtectedBranchPost(ctx *context.Context, f auth.ProtectBranchForm)
|
||||
if strings.TrimSpace(f.MergeWhitelistTeams) != "" {
|
||||
mergeWhitelistTeams, _ = base.StringsToInt64s(strings.Split(f.MergeWhitelistTeams, ","))
|
||||
}
|
||||
|
||||
protectBranch.EnableStatusCheck = f.EnableStatusCheck
|
||||
protectBranch.StatusCheckContexts = f.StatusCheckContexts
|
||||
|
||||
protectBranch.RequiredApprovals = f.RequiredApprovals
|
||||
if strings.TrimSpace(f.ApprovalsWhitelistUsers) != "" {
|
||||
approvalsWhitelistUsers, _ = base.StringsToInt64s(strings.Split(f.ApprovalsWhitelistUsers, ","))
|
||||
|
Reference in New Issue
Block a user