Signed-off-by: a1012112796 <1012112796@qq.com> Co-authored-by: Lauris BH <lauris@nix.lv>tags/v1.15.0-dev
@@ -21,28 +21,29 @@ import ( | |||
// ProtectedBranch struct | |||
type ProtectedBranch struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
RepoID int64 `xorm:"UNIQUE(s)"` | |||
BranchName string `xorm:"UNIQUE(s)"` | |||
CanPush bool `xorm:"NOT NULL DEFAULT false"` | |||
EnableWhitelist bool | |||
WhitelistUserIDs []int64 `xorm:"JSON TEXT"` | |||
WhitelistTeamIDs []int64 `xorm:"JSON TEXT"` | |||
EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"` | |||
WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"` | |||
MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"` | |||
MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"` | |||
EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"` | |||
StatusCheckContexts []string `xorm:"JSON TEXT"` | |||
EnableApprovalsWhitelist bool `xorm:"NOT NULL DEFAULT false"` | |||
ApprovalsWhitelistUserIDs []int64 `xorm:"JSON TEXT"` | |||
ApprovalsWhitelistTeamIDs []int64 `xorm:"JSON TEXT"` | |||
RequiredApprovals int64 `xorm:"NOT NULL DEFAULT 0"` | |||
BlockOnRejectedReviews bool `xorm:"NOT NULL DEFAULT false"` | |||
BlockOnOutdatedBranch bool `xorm:"NOT NULL DEFAULT false"` | |||
DismissStaleApprovals bool `xorm:"NOT NULL DEFAULT false"` | |||
RequireSignedCommits bool `xorm:"NOT NULL DEFAULT false"` | |||
ProtectedFilePatterns string `xorm:"TEXT"` | |||
ID int64 `xorm:"pk autoincr"` | |||
RepoID int64 `xorm:"UNIQUE(s)"` | |||
BranchName string `xorm:"UNIQUE(s)"` | |||
CanPush bool `xorm:"NOT NULL DEFAULT false"` | |||
EnableWhitelist bool | |||
WhitelistUserIDs []int64 `xorm:"JSON TEXT"` | |||
WhitelistTeamIDs []int64 `xorm:"JSON TEXT"` | |||
EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"` | |||
WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"` | |||
MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"` | |||
MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"` | |||
EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"` | |||
StatusCheckContexts []string `xorm:"JSON TEXT"` | |||
EnableApprovalsWhitelist bool `xorm:"NOT NULL DEFAULT false"` | |||
ApprovalsWhitelistUserIDs []int64 `xorm:"JSON TEXT"` | |||
ApprovalsWhitelistTeamIDs []int64 `xorm:"JSON TEXT"` | |||
RequiredApprovals int64 `xorm:"NOT NULL DEFAULT 0"` | |||
BlockOnRejectedReviews bool `xorm:"NOT NULL DEFAULT false"` | |||
BlockOnOfficialReviewRequests bool `xorm:"NOT NULL DEFAULT false"` | |||
BlockOnOutdatedBranch bool `xorm:"NOT NULL DEFAULT false"` | |||
DismissStaleApprovals bool `xorm:"NOT NULL DEFAULT false"` | |||
RequireSignedCommits bool `xorm:"NOT NULL DEFAULT false"` | |||
ProtectedFilePatterns string `xorm:"TEXT"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | |||
@@ -171,13 +172,12 @@ func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) | |||
} | |||
// MergeBlockedByRejectedReview returns true if merge is blocked by rejected reviews | |||
// An official ReviewRequest should also block Merge like Reject | |||
func (protectBranch *ProtectedBranch) MergeBlockedByRejectedReview(pr *PullRequest) bool { | |||
if !protectBranch.BlockOnRejectedReviews { | |||
return false | |||
} | |||
rejectExist, err := x.Where("issue_id = ?", pr.IssueID). | |||
And("type in ( ?, ?)", ReviewTypeReject, ReviewTypeRequest). | |||
And("type = ?", ReviewTypeReject). | |||
And("official = ?", true). | |||
Exist(new(Review)) | |||
if err != nil { | |||
@@ -188,6 +188,24 @@ func (protectBranch *ProtectedBranch) MergeBlockedByRejectedReview(pr *PullReque | |||
return rejectExist | |||
} | |||
// MergeBlockedByOfficialReviewRequests block merge because of some review request to official reviewer | |||
// of from official review | |||
func (protectBranch *ProtectedBranch) MergeBlockedByOfficialReviewRequests(pr *PullRequest) bool { | |||
if !protectBranch.BlockOnOfficialReviewRequests { | |||
return false | |||
} | |||
has, err := x.Where("issue_id = ?", pr.IssueID). | |||
And("type = ?", ReviewTypeRequest). | |||
And("official = ?", true). | |||
Exist(new(Review)) | |||
if err != nil { | |||
log.Error("MergeBlockedByOfficialReviewRequests: %v", err) | |||
return true | |||
} | |||
return has | |||
} | |||
// MergeBlockedByOutdatedBranch returns true if merge is blocked by an outdated head branch | |||
func (protectBranch *ProtectedBranch) MergeBlockedByOutdatedBranch(pr *PullRequest) bool { | |||
return protectBranch.BlockOnOutdatedBranch && pr.CommitsBehind > 0 | |||
@@ -254,6 +254,8 @@ var migrations = []Migration{ | |||
NewMigration("code comment replies should have the commitID of the review they are replying to", updateCodeCommentReplies), | |||
// v159 -> v160 | |||
NewMigration("update reactions constraint", updateReactionConstraint), | |||
// v160 -> v161 | |||
NewMigration("Add block on official review requests branch protection", addBlockOnOfficialReviewRequests), | |||
} | |||
// GetCurrentDBVersion returns the current db version | |||
@@ -0,0 +1,17 @@ | |||
// Copyright 2020 The Gitea Authors. All rights reserved. | |||
// Use of this source code is governed by a MIT-style | |||
// license that can be found in the LICENSE file. | |||
package migrations | |||
import ( | |||
"xorm.io/xorm" | |||
) | |||
func addBlockOnOfficialReviewRequests(x *xorm.Engine) error { | |||
type ProtectedBranch struct { | |||
BlockOnOfficialReviewRequests bool `xorm:"NOT NULL DEFAULT false"` | |||
} | |||
return x.Sync2(new(ProtectedBranch)) | |||
} |
@@ -178,25 +178,26 @@ func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) bi | |||
// ProtectBranchForm form for changing protected branch settings | |||
type ProtectBranchForm struct { | |||
Protected bool | |||
EnablePush string | |||
WhitelistUsers string | |||
WhitelistTeams string | |||
WhitelistDeployKeys bool | |||
EnableMergeWhitelist bool | |||
MergeWhitelistUsers string | |||
MergeWhitelistTeams string | |||
EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"` | |||
StatusCheckContexts []string | |||
RequiredApprovals int64 | |||
EnableApprovalsWhitelist bool | |||
ApprovalsWhitelistUsers string | |||
ApprovalsWhitelistTeams string | |||
BlockOnRejectedReviews bool | |||
BlockOnOutdatedBranch bool | |||
DismissStaleApprovals bool | |||
RequireSignedCommits bool | |||
ProtectedFilePatterns string | |||
Protected bool | |||
EnablePush string | |||
WhitelistUsers string | |||
WhitelistTeams string | |||
WhitelistDeployKeys bool | |||
EnableMergeWhitelist bool | |||
MergeWhitelistUsers string | |||
MergeWhitelistTeams string | |||
EnableStatusCheck bool | |||
StatusCheckContexts []string | |||
RequiredApprovals int64 | |||
EnableApprovalsWhitelist bool | |||
ApprovalsWhitelistUsers string | |||
ApprovalsWhitelistTeams string | |||
BlockOnRejectedReviews bool | |||
BlockOnOfficialReviewRequests bool | |||
BlockOnOutdatedBranch bool | |||
DismissStaleApprovals bool | |||
RequireSignedCommits bool | |||
ProtectedFilePatterns string | |||
} | |||
// Validate validates the fields | |||
@@ -105,28 +105,29 @@ func ToBranchProtection(bp *models.ProtectedBranch) *api.BranchProtection { | |||
} | |||
return &api.BranchProtection{ | |||
BranchName: bp.BranchName, | |||
EnablePush: bp.CanPush, | |||
EnablePushWhitelist: bp.EnableWhitelist, | |||
PushWhitelistUsernames: pushWhitelistUsernames, | |||
PushWhitelistTeams: pushWhitelistTeams, | |||
PushWhitelistDeployKeys: bp.WhitelistDeployKeys, | |||
EnableMergeWhitelist: bp.EnableMergeWhitelist, | |||
MergeWhitelistUsernames: mergeWhitelistUsernames, | |||
MergeWhitelistTeams: mergeWhitelistTeams, | |||
EnableStatusCheck: bp.EnableStatusCheck, | |||
StatusCheckContexts: bp.StatusCheckContexts, | |||
RequiredApprovals: bp.RequiredApprovals, | |||
EnableApprovalsWhitelist: bp.EnableApprovalsWhitelist, | |||
ApprovalsWhitelistUsernames: approvalsWhitelistUsernames, | |||
ApprovalsWhitelistTeams: approvalsWhitelistTeams, | |||
BlockOnRejectedReviews: bp.BlockOnRejectedReviews, | |||
BlockOnOutdatedBranch: bp.BlockOnOutdatedBranch, | |||
DismissStaleApprovals: bp.DismissStaleApprovals, | |||
RequireSignedCommits: bp.RequireSignedCommits, | |||
ProtectedFilePatterns: bp.ProtectedFilePatterns, | |||
Created: bp.CreatedUnix.AsTime(), | |||
Updated: bp.UpdatedUnix.AsTime(), | |||
BranchName: bp.BranchName, | |||
EnablePush: bp.CanPush, | |||
EnablePushWhitelist: bp.EnableWhitelist, | |||
PushWhitelistUsernames: pushWhitelistUsernames, | |||
PushWhitelistTeams: pushWhitelistTeams, | |||
PushWhitelistDeployKeys: bp.WhitelistDeployKeys, | |||
EnableMergeWhitelist: bp.EnableMergeWhitelist, | |||
MergeWhitelistUsernames: mergeWhitelistUsernames, | |||
MergeWhitelistTeams: mergeWhitelistTeams, | |||
EnableStatusCheck: bp.EnableStatusCheck, | |||
StatusCheckContexts: bp.StatusCheckContexts, | |||
RequiredApprovals: bp.RequiredApprovals, | |||
EnableApprovalsWhitelist: bp.EnableApprovalsWhitelist, | |||
ApprovalsWhitelistUsernames: approvalsWhitelistUsernames, | |||
ApprovalsWhitelistTeams: approvalsWhitelistTeams, | |||
BlockOnRejectedReviews: bp.BlockOnRejectedReviews, | |||
BlockOnOfficialReviewRequests: bp.BlockOnOfficialReviewRequests, | |||
BlockOnOutdatedBranch: bp.BlockOnOutdatedBranch, | |||
DismissStaleApprovals: bp.DismissStaleApprovals, | |||
RequireSignedCommits: bp.RequireSignedCommits, | |||
ProtectedFilePatterns: bp.ProtectedFilePatterns, | |||
Created: bp.CreatedUnix.AsTime(), | |||
Updated: bp.UpdatedUnix.AsTime(), | |||
} | |||
} | |||
@@ -23,26 +23,27 @@ type Branch struct { | |||
// BranchProtection represents a branch protection for a repository | |||
type BranchProtection struct { | |||
BranchName string `json:"branch_name"` | |||
EnablePush bool `json:"enable_push"` | |||
EnablePushWhitelist bool `json:"enable_push_whitelist"` | |||
PushWhitelistUsernames []string `json:"push_whitelist_usernames"` | |||
PushWhitelistTeams []string `json:"push_whitelist_teams"` | |||
PushWhitelistDeployKeys bool `json:"push_whitelist_deploy_keys"` | |||
EnableMergeWhitelist bool `json:"enable_merge_whitelist"` | |||
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"` | |||
MergeWhitelistTeams []string `json:"merge_whitelist_teams"` | |||
EnableStatusCheck bool `json:"enable_status_check"` | |||
StatusCheckContexts []string `json:"status_check_contexts"` | |||
RequiredApprovals int64 `json:"required_approvals"` | |||
EnableApprovalsWhitelist bool `json:"enable_approvals_whitelist"` | |||
ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"` | |||
ApprovalsWhitelistTeams []string `json:"approvals_whitelist_teams"` | |||
BlockOnRejectedReviews bool `json:"block_on_rejected_reviews"` | |||
BlockOnOutdatedBranch bool `json:"block_on_outdated_branch"` | |||
DismissStaleApprovals bool `json:"dismiss_stale_approvals"` | |||
RequireSignedCommits bool `json:"require_signed_commits"` | |||
ProtectedFilePatterns string `json:"protected_file_patterns"` | |||
BranchName string `json:"branch_name"` | |||
EnablePush bool `json:"enable_push"` | |||
EnablePushWhitelist bool `json:"enable_push_whitelist"` | |||
PushWhitelistUsernames []string `json:"push_whitelist_usernames"` | |||
PushWhitelistTeams []string `json:"push_whitelist_teams"` | |||
PushWhitelistDeployKeys bool `json:"push_whitelist_deploy_keys"` | |||
EnableMergeWhitelist bool `json:"enable_merge_whitelist"` | |||
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"` | |||
MergeWhitelistTeams []string `json:"merge_whitelist_teams"` | |||
EnableStatusCheck bool `json:"enable_status_check"` | |||
StatusCheckContexts []string `json:"status_check_contexts"` | |||
RequiredApprovals int64 `json:"required_approvals"` | |||
EnableApprovalsWhitelist bool `json:"enable_approvals_whitelist"` | |||
ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"` | |||
ApprovalsWhitelistTeams []string `json:"approvals_whitelist_teams"` | |||
BlockOnRejectedReviews bool `json:"block_on_rejected_reviews"` | |||
BlockOnOfficialReviewRequests bool `json:"block_on_official_review_requests"` | |||
BlockOnOutdatedBranch bool `json:"block_on_outdated_branch"` | |||
DismissStaleApprovals bool `json:"dismiss_stale_approvals"` | |||
RequireSignedCommits bool `json:"require_signed_commits"` | |||
ProtectedFilePatterns string `json:"protected_file_patterns"` | |||
// swagger:strfmt date-time | |||
Created time.Time `json:"created_at"` | |||
// swagger:strfmt date-time | |||
@@ -51,47 +52,49 @@ type BranchProtection struct { | |||
// CreateBranchProtectionOption options for creating a branch protection | |||
type CreateBranchProtectionOption struct { | |||
BranchName string `json:"branch_name"` | |||
EnablePush bool `json:"enable_push"` | |||
EnablePushWhitelist bool `json:"enable_push_whitelist"` | |||
PushWhitelistUsernames []string `json:"push_whitelist_usernames"` | |||
PushWhitelistTeams []string `json:"push_whitelist_teams"` | |||
PushWhitelistDeployKeys bool `json:"push_whitelist_deploy_keys"` | |||
EnableMergeWhitelist bool `json:"enable_merge_whitelist"` | |||
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"` | |||
MergeWhitelistTeams []string `json:"merge_whitelist_teams"` | |||
EnableStatusCheck bool `json:"enable_status_check"` | |||
StatusCheckContexts []string `json:"status_check_contexts"` | |||
RequiredApprovals int64 `json:"required_approvals"` | |||
EnableApprovalsWhitelist bool `json:"enable_approvals_whitelist"` | |||
ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"` | |||
ApprovalsWhitelistTeams []string `json:"approvals_whitelist_teams"` | |||
BlockOnRejectedReviews bool `json:"block_on_rejected_reviews"` | |||
BlockOnOutdatedBranch bool `json:"block_on_outdated_branch"` | |||
DismissStaleApprovals bool `json:"dismiss_stale_approvals"` | |||
RequireSignedCommits bool `json:"require_signed_commits"` | |||
ProtectedFilePatterns string `json:"protected_file_patterns"` | |||
BranchName string `json:"branch_name"` | |||
EnablePush bool `json:"enable_push"` | |||
EnablePushWhitelist bool `json:"enable_push_whitelist"` | |||
PushWhitelistUsernames []string `json:"push_whitelist_usernames"` | |||
PushWhitelistTeams []string `json:"push_whitelist_teams"` | |||
PushWhitelistDeployKeys bool `json:"push_whitelist_deploy_keys"` | |||
EnableMergeWhitelist bool `json:"enable_merge_whitelist"` | |||
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"` | |||
MergeWhitelistTeams []string `json:"merge_whitelist_teams"` | |||
EnableStatusCheck bool `json:"enable_status_check"` | |||
StatusCheckContexts []string `json:"status_check_contexts"` | |||
RequiredApprovals int64 `json:"required_approvals"` | |||
EnableApprovalsWhitelist bool `json:"enable_approvals_whitelist"` | |||
ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"` | |||
ApprovalsWhitelistTeams []string `json:"approvals_whitelist_teams"` | |||
BlockOnRejectedReviews bool `json:"block_on_rejected_reviews"` | |||
BlockOnOfficialReviewRequests bool `json:"block_on_official_review_requests"` | |||
BlockOnOutdatedBranch bool `json:"block_on_outdated_branch"` | |||
DismissStaleApprovals bool `json:"dismiss_stale_approvals"` | |||
RequireSignedCommits bool `json:"require_signed_commits"` | |||
ProtectedFilePatterns string `json:"protected_file_patterns"` | |||
} | |||
// EditBranchProtectionOption options for editing a branch protection | |||
type EditBranchProtectionOption struct { | |||
EnablePush *bool `json:"enable_push"` | |||
EnablePushWhitelist *bool `json:"enable_push_whitelist"` | |||
PushWhitelistUsernames []string `json:"push_whitelist_usernames"` | |||
PushWhitelistTeams []string `json:"push_whitelist_teams"` | |||
PushWhitelistDeployKeys *bool `json:"push_whitelist_deploy_keys"` | |||
EnableMergeWhitelist *bool `json:"enable_merge_whitelist"` | |||
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"` | |||
MergeWhitelistTeams []string `json:"merge_whitelist_teams"` | |||
EnableStatusCheck *bool `json:"enable_status_check"` | |||
StatusCheckContexts []string `json:"status_check_contexts"` | |||
RequiredApprovals *int64 `json:"required_approvals"` | |||
EnableApprovalsWhitelist *bool `json:"enable_approvals_whitelist"` | |||
ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"` | |||
ApprovalsWhitelistTeams []string `json:"approvals_whitelist_teams"` | |||
BlockOnRejectedReviews *bool `json:"block_on_rejected_reviews"` | |||
BlockOnOutdatedBranch *bool `json:"block_on_outdated_branch"` | |||
DismissStaleApprovals *bool `json:"dismiss_stale_approvals"` | |||
RequireSignedCommits *bool `json:"require_signed_commits"` | |||
ProtectedFilePatterns *string `json:"protected_file_patterns"` | |||
EnablePush *bool `json:"enable_push"` | |||
EnablePushWhitelist *bool `json:"enable_push_whitelist"` | |||
PushWhitelistUsernames []string `json:"push_whitelist_usernames"` | |||
PushWhitelistTeams []string `json:"push_whitelist_teams"` | |||
PushWhitelistDeployKeys *bool `json:"push_whitelist_deploy_keys"` | |||
EnableMergeWhitelist *bool `json:"enable_merge_whitelist"` | |||
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"` | |||
MergeWhitelistTeams []string `json:"merge_whitelist_teams"` | |||
EnableStatusCheck *bool `json:"enable_status_check"` | |||
StatusCheckContexts []string `json:"status_check_contexts"` | |||
RequiredApprovals *int64 `json:"required_approvals"` | |||
EnableApprovalsWhitelist *bool `json:"enable_approvals_whitelist"` | |||
ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"` | |||
ApprovalsWhitelistTeams []string `json:"approvals_whitelist_teams"` | |||
BlockOnRejectedReviews *bool `json:"block_on_rejected_reviews"` | |||
BlockOnOfficialReviewRequests *bool `json:"block_on_official_review_requests"` | |||
BlockOnOutdatedBranch *bool `json:"block_on_outdated_branch"` | |||
DismissStaleApprovals *bool `json:"dismiss_stale_approvals"` | |||
RequireSignedCommits *bool `json:"require_signed_commits"` | |||
ProtectedFilePatterns *string `json:"protected_file_patterns"` | |||
} |
@@ -1244,6 +1244,7 @@ pulls.required_status_check_missing = Some required checks are missing. | |||
pulls.required_status_check_administrator = As an administrator, you may still merge this pull request. | |||
pulls.blocked_by_approvals = "This Pull Request doesn't have enough approvals yet. %d of %d approvals granted." | |||
pulls.blocked_by_rejection = "This Pull Request has changes requested by an official reviewer." | |||
pulls.blocked_by_official_review_requests = "This Pull Request has official review requests." | |||
pulls.blocked_by_outdated_branch = "This Pull Request is blocked because it's outdated." | |||
pulls.blocked_by_changed_protected_files_1= "This Pull Request is blocked because it changes a protected file:" | |||
pulls.blocked_by_changed_protected_files_n= "This Pull Request is blocked because it changes protected files:" | |||
@@ -1707,6 +1708,8 @@ settings.protected_branch_deletion = Disable Branch Protection | |||
settings.protected_branch_deletion_desc = Disabling branch protection allows users with write permission to push to the branch. Continue? | |||
settings.block_rejected_reviews = Block merge on rejected reviews | |||
settings.block_rejected_reviews_desc = Merging will not be possible when changes are requested by official reviewers, even if there are enough approvals. | |||
settings.block_on_official_review_requests = Block merge on official review requests | |||
settings.block_on_official_review_requests_desc = Merging will not be possible when it has official review requests, even if there are enough approvals. | |||
settings.block_outdated_branch = Block merge if pull request is outdated | |||
settings.block_outdated_branch_desc = Merging will not be possible when head branch is behind base branch. | |||
settings.default_branch_desc = Select a default repository branch for pull requests and code commits: | |||
@@ -509,21 +509,22 @@ func CreateBranchProtection(ctx *context.APIContext, form api.CreateBranchProtec | |||
} | |||
protectBranch = &models.ProtectedBranch{ | |||
RepoID: ctx.Repo.Repository.ID, | |||
BranchName: form.BranchName, | |||
CanPush: form.EnablePush, | |||
EnableWhitelist: form.EnablePush && form.EnablePushWhitelist, | |||
EnableMergeWhitelist: form.EnableMergeWhitelist, | |||
WhitelistDeployKeys: form.EnablePush && form.EnablePushWhitelist && form.PushWhitelistDeployKeys, | |||
EnableStatusCheck: form.EnableStatusCheck, | |||
StatusCheckContexts: form.StatusCheckContexts, | |||
EnableApprovalsWhitelist: form.EnableApprovalsWhitelist, | |||
RequiredApprovals: requiredApprovals, | |||
BlockOnRejectedReviews: form.BlockOnRejectedReviews, | |||
DismissStaleApprovals: form.DismissStaleApprovals, | |||
RequireSignedCommits: form.RequireSignedCommits, | |||
ProtectedFilePatterns: form.ProtectedFilePatterns, | |||
BlockOnOutdatedBranch: form.BlockOnOutdatedBranch, | |||
RepoID: ctx.Repo.Repository.ID, | |||
BranchName: form.BranchName, | |||
CanPush: form.EnablePush, | |||
EnableWhitelist: form.EnablePush && form.EnablePushWhitelist, | |||
EnableMergeWhitelist: form.EnableMergeWhitelist, | |||
WhitelistDeployKeys: form.EnablePush && form.EnablePushWhitelist && form.PushWhitelistDeployKeys, | |||
EnableStatusCheck: form.EnableStatusCheck, | |||
StatusCheckContexts: form.StatusCheckContexts, | |||
EnableApprovalsWhitelist: form.EnableApprovalsWhitelist, | |||
RequiredApprovals: requiredApprovals, | |||
BlockOnRejectedReviews: form.BlockOnRejectedReviews, | |||
BlockOnOfficialReviewRequests: form.BlockOnOfficialReviewRequests, | |||
DismissStaleApprovals: form.DismissStaleApprovals, | |||
RequireSignedCommits: form.RequireSignedCommits, | |||
ProtectedFilePatterns: form.ProtectedFilePatterns, | |||
BlockOnOutdatedBranch: form.BlockOnOutdatedBranch, | |||
} | |||
err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, models.WhitelistOptions{ | |||
@@ -652,6 +653,10 @@ func EditBranchProtection(ctx *context.APIContext, form api.EditBranchProtection | |||
protectBranch.BlockOnRejectedReviews = *form.BlockOnRejectedReviews | |||
} | |||
if form.BlockOnOfficialReviewRequests != nil { | |||
protectBranch.BlockOnOfficialReviewRequests = *form.BlockOnOfficialReviewRequests | |||
} | |||
if form.DismissStaleApprovals != nil { | |||
protectBranch.DismissStaleApprovals = *form.DismissStaleApprovals | |||
} | |||
@@ -1455,6 +1455,7 @@ func ViewIssue(ctx *context.Context) { | |||
cnt := pull.ProtectedBranch.GetGrantedApprovalsCount(pull) | |||
ctx.Data["IsBlockedByApprovals"] = !pull.ProtectedBranch.HasEnoughApprovals(pull) | |||
ctx.Data["IsBlockedByRejection"] = pull.ProtectedBranch.MergeBlockedByRejectedReview(pull) | |||
ctx.Data["IsBlockedByOfficialReviewRequests"] = pull.ProtectedBranch.MergeBlockedByOfficialReviewRequests(pull) | |||
ctx.Data["IsBlockedByOutdatedBranch"] = pull.ProtectedBranch.MergeBlockedByOutdatedBranch(pull) | |||
ctx.Data["GrantedApprovals"] = cnt | |||
ctx.Data["RequireSigned"] = pull.ProtectedBranch.RequireSignedCommits | |||
@@ -246,6 +246,7 @@ func SettingsProtectedBranchPost(ctx *context.Context, f auth.ProtectBranchForm) | |||
} | |||
} | |||
protectBranch.BlockOnRejectedReviews = f.BlockOnRejectedReviews | |||
protectBranch.BlockOnOfficialReviewRequests = f.BlockOnOfficialReviewRequests | |||
protectBranch.DismissStaleApprovals = f.DismissStaleApprovals | |||
protectBranch.RequireSignedCommits = f.RequireSignedCommits | |||
protectBranch.ProtectedFilePatterns = f.ProtectedFilePatterns | |||
@@ -591,6 +591,11 @@ func CheckPRReadyToMerge(pr *models.PullRequest, skipProtectedFilesCheck bool) ( | |||
Reason: "There are requested changes", | |||
} | |||
} | |||
if pr.ProtectedBranch.MergeBlockedByOfficialReviewRequests(pr) { | |||
return models.ErrNotAllowedToMerge{ | |||
Reason: "There are official review requests", | |||
} | |||
} | |||
if pr.ProtectedBranch.MergeBlockedByOutdatedBranch(pr) { | |||
return models.ErrNotAllowedToMerge{ | |||
@@ -84,6 +84,7 @@ | |||
{{- else if .IsPullRequestBroken}}red | |||
{{- else if .IsBlockedByApprovals}}red | |||
{{- else if .IsBlockedByRejection}}red | |||
{{- else if .IsBlockedByOfficialReviewRequests}}red | |||
{{- else if .IsBlockedByOutdatedBranch}}red | |||
{{- else if .IsBlockedByChangedProtectedFiles}}red | |||
{{- else if and .EnableStatusCheck (or .RequiredStatusCheckState.IsFailure .RequiredStatusCheckState.IsError)}}red | |||
@@ -159,6 +160,11 @@ | |||
<i class="icon icon-octicon">{{svg "octicon-x"}}</i> | |||
{{$.i18n.Tr "repo.pulls.blocked_by_rejection"}} | |||
</div> | |||
{{else if .IsBlockedByOfficialReviewRequests}} | |||
<div class="item"> | |||
<i class="icon icon-octicon">{{svg "octicon-x"}}</i> | |||
{{$.i18n.Tr "repo.pulls.blocked_by_official_review_requests"}} | |||
</div> | |||
{{else if .IsBlockedByOutdatedBranch}} | |||
<div class="item"> | |||
<i class="icon icon-octicon">{{svg "octicon-x"}}</i> | |||
@@ -194,7 +200,7 @@ | |||
{{$.i18n.Tr (printf "repo.signing.wont_sign.%s" .WontSignReason) }} | |||
</div> | |||
{{end}} | |||
{{$notAllOverridableChecksOk := or .IsBlockedByApprovals .IsBlockedByRejection .IsBlockedByOutdatedBranch .IsBlockedByChangedProtectedFiles (and .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess))}} | |||
{{$notAllOverridableChecksOk := or .IsBlockedByApprovals .IsBlockedByRejection .IsBlockedByOfficialReviewRequests .IsBlockedByOutdatedBranch .IsBlockedByChangedProtectedFiles (and .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess))}} | |||
{{if and (or $.IsRepoAdmin (not $notAllOverridableChecksOk)) (or (not .AllowMerge) (not .RequireSigned) .WillSign)}} | |||
{{if $notAllOverridableChecksOk}} | |||
<div class="item"> | |||
@@ -384,7 +390,12 @@ | |||
{{else if .IsBlockedByRejection}} | |||
<div class="item text red"> | |||
{{svg "octicon-x"}} | |||
{{$.i18n.Tr "repo.pulls.blocked_by_rejection"}} | |||
{{$.i18n.Tr "repo.pulls.blocked_by_rejection"}} | |||
</div> | |||
{{else if .IsBlockedByOfficialReviewRequests}} | |||
<div class="item text red"> | |||
{{svg "octicon-x"}} | |||
{{$.i18n.Tr "repo.pulls.blocked_by_official_review_requests"}} | |||
</div> | |||
{{else if .IsBlockedByOutdatedBranch}} | |||
<div class="item text red"> | |||
@@ -213,6 +213,13 @@ | |||
</div> | |||
<div class="field"> | |||
<div class="ui checkbox"> | |||
<input name="block_on_official_review_requests" type="checkbox" {{if .Branch.BlockOnOfficialReviewRequests}}checked{{end}}> | |||
<label for="block_on_official_review_requests">{{.i18n.Tr "repo.settings.block_on_official_review_requests"}}</label> | |||
<p class="help">{{.i18n.Tr "repo.settings.block_on_official_review_requests_desc"}}</p> | |||
</div> | |||
</div> | |||
<div class="field"> | |||
<div class="ui checkbox"> | |||
<input name="dismiss_stale_approvals" type="checkbox" {{if .Branch.DismissStaleApprovals}}checked{{end}}> | |||
<label for="dismiss_stale_approvals">{{.i18n.Tr "repo.settings.dismiss_stale_approvals"}}</label> | |||
<p class="help">{{.i18n.Tr "repo.settings.dismiss_stale_approvals_desc"}}</p> | |||
@@ -11326,6 +11326,10 @@ | |||
}, | |||
"x-go-name": "ApprovalsWhitelistUsernames" | |||
}, | |||
"block_on_official_review_requests": { | |||
"type": "boolean", | |||
"x-go-name": "BlockOnOfficialReviewRequests" | |||
}, | |||
"block_on_outdated_branch": { | |||
"type": "boolean", | |||
"x-go-name": "BlockOnOutdatedBranch" | |||
@@ -11660,6 +11664,10 @@ | |||
}, | |||
"x-go-name": "ApprovalsWhitelistUsernames" | |||
}, | |||
"block_on_official_review_requests": { | |||
"type": "boolean", | |||
"x-go-name": "BlockOnOfficialReviewRequests" | |||
}, | |||
"block_on_outdated_branch": { | |||
"type": "boolean", | |||
"x-go-name": "BlockOnOutdatedBranch" | |||
@@ -12605,6 +12613,10 @@ | |||
}, | |||
"x-go-name": "ApprovalsWhitelistUsernames" | |||
}, | |||
"block_on_official_review_requests": { | |||
"type": "boolean", | |||
"x-go-name": "BlockOnOfficialReviewRequests" | |||
}, | |||
"block_on_outdated_branch": { | |||
"type": "boolean", | |||
"x-go-name": "BlockOnOutdatedBranch" | |||