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 | // ProtectedBranch struct | ||||
type 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"` | CreatedUnix timeutil.TimeStamp `xorm:"created"` | ||||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | 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 | // 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 { | func (protectBranch *ProtectedBranch) MergeBlockedByRejectedReview(pr *PullRequest) bool { | ||||
if !protectBranch.BlockOnRejectedReviews { | if !protectBranch.BlockOnRejectedReviews { | ||||
return false | return false | ||||
} | } | ||||
rejectExist, err := x.Where("issue_id = ?", pr.IssueID). | rejectExist, err := x.Where("issue_id = ?", pr.IssueID). | ||||
And("type in ( ?, ?)", ReviewTypeReject, ReviewTypeRequest). | |||||
And("type = ?", ReviewTypeReject). | |||||
And("official = ?", true). | And("official = ?", true). | ||||
Exist(new(Review)) | Exist(new(Review)) | ||||
if err != nil { | if err != nil { | ||||
@@ -188,6 +188,24 @@ func (protectBranch *ProtectedBranch) MergeBlockedByRejectedReview(pr *PullReque | |||||
return rejectExist | 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 | // MergeBlockedByOutdatedBranch returns true if merge is blocked by an outdated head branch | ||||
func (protectBranch *ProtectedBranch) MergeBlockedByOutdatedBranch(pr *PullRequest) bool { | func (protectBranch *ProtectedBranch) MergeBlockedByOutdatedBranch(pr *PullRequest) bool { | ||||
return protectBranch.BlockOnOutdatedBranch && pr.CommitsBehind > 0 | 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), | NewMigration("code comment replies should have the commitID of the review they are replying to", updateCodeCommentReplies), | ||||
// v159 -> v160 | // v159 -> v160 | ||||
NewMigration("update reactions constraint", updateReactionConstraint), | NewMigration("update reactions constraint", updateReactionConstraint), | ||||
// v160 -> v161 | |||||
NewMigration("Add block on official review requests branch protection", addBlockOnOfficialReviewRequests), | |||||
} | } | ||||
// GetCurrentDBVersion returns the current db version | // 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 | // ProtectBranchForm form for changing protected branch settings | ||||
type ProtectBranchForm struct { | 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 | // Validate validates the fields | ||||
@@ -105,28 +105,29 @@ func ToBranchProtection(bp *models.ProtectedBranch) *api.BranchProtection { | |||||
} | } | ||||
return &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 | // BranchProtection represents a branch protection for a repository | ||||
type BranchProtection struct { | 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 | // swagger:strfmt date-time | ||||
Created time.Time `json:"created_at"` | Created time.Time `json:"created_at"` | ||||
// swagger:strfmt date-time | // swagger:strfmt date-time | ||||
@@ -51,47 +52,49 @@ type BranchProtection struct { | |||||
// CreateBranchProtectionOption options for creating a branch protection | // CreateBranchProtectionOption options for creating a branch protection | ||||
type CreateBranchProtectionOption struct { | 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 | // EditBranchProtectionOption options for editing a branch protection | ||||
type EditBranchProtectionOption struct { | 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.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_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_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_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_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:" | 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.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 = 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_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 = 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.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: | 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{ | 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{ | 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 | protectBranch.BlockOnRejectedReviews = *form.BlockOnRejectedReviews | ||||
} | } | ||||
if form.BlockOnOfficialReviewRequests != nil { | |||||
protectBranch.BlockOnOfficialReviewRequests = *form.BlockOnOfficialReviewRequests | |||||
} | |||||
if form.DismissStaleApprovals != nil { | if form.DismissStaleApprovals != nil { | ||||
protectBranch.DismissStaleApprovals = *form.DismissStaleApprovals | protectBranch.DismissStaleApprovals = *form.DismissStaleApprovals | ||||
} | } | ||||
@@ -1455,6 +1455,7 @@ func ViewIssue(ctx *context.Context) { | |||||
cnt := pull.ProtectedBranch.GetGrantedApprovalsCount(pull) | cnt := pull.ProtectedBranch.GetGrantedApprovalsCount(pull) | ||||
ctx.Data["IsBlockedByApprovals"] = !pull.ProtectedBranch.HasEnoughApprovals(pull) | ctx.Data["IsBlockedByApprovals"] = !pull.ProtectedBranch.HasEnoughApprovals(pull) | ||||
ctx.Data["IsBlockedByRejection"] = pull.ProtectedBranch.MergeBlockedByRejectedReview(pull) | ctx.Data["IsBlockedByRejection"] = pull.ProtectedBranch.MergeBlockedByRejectedReview(pull) | ||||
ctx.Data["IsBlockedByOfficialReviewRequests"] = pull.ProtectedBranch.MergeBlockedByOfficialReviewRequests(pull) | |||||
ctx.Data["IsBlockedByOutdatedBranch"] = pull.ProtectedBranch.MergeBlockedByOutdatedBranch(pull) | ctx.Data["IsBlockedByOutdatedBranch"] = pull.ProtectedBranch.MergeBlockedByOutdatedBranch(pull) | ||||
ctx.Data["GrantedApprovals"] = cnt | ctx.Data["GrantedApprovals"] = cnt | ||||
ctx.Data["RequireSigned"] = pull.ProtectedBranch.RequireSignedCommits | ctx.Data["RequireSigned"] = pull.ProtectedBranch.RequireSignedCommits | ||||
@@ -246,6 +246,7 @@ func SettingsProtectedBranchPost(ctx *context.Context, f auth.ProtectBranchForm) | |||||
} | } | ||||
} | } | ||||
protectBranch.BlockOnRejectedReviews = f.BlockOnRejectedReviews | protectBranch.BlockOnRejectedReviews = f.BlockOnRejectedReviews | ||||
protectBranch.BlockOnOfficialReviewRequests = f.BlockOnOfficialReviewRequests | |||||
protectBranch.DismissStaleApprovals = f.DismissStaleApprovals | protectBranch.DismissStaleApprovals = f.DismissStaleApprovals | ||||
protectBranch.RequireSignedCommits = f.RequireSignedCommits | protectBranch.RequireSignedCommits = f.RequireSignedCommits | ||||
protectBranch.ProtectedFilePatterns = f.ProtectedFilePatterns | protectBranch.ProtectedFilePatterns = f.ProtectedFilePatterns | ||||
@@ -591,6 +591,11 @@ func CheckPRReadyToMerge(pr *models.PullRequest, skipProtectedFilesCheck bool) ( | |||||
Reason: "There are requested changes", | Reason: "There are requested changes", | ||||
} | } | ||||
} | } | ||||
if pr.ProtectedBranch.MergeBlockedByOfficialReviewRequests(pr) { | |||||
return models.ErrNotAllowedToMerge{ | |||||
Reason: "There are official review requests", | |||||
} | |||||
} | |||||
if pr.ProtectedBranch.MergeBlockedByOutdatedBranch(pr) { | if pr.ProtectedBranch.MergeBlockedByOutdatedBranch(pr) { | ||||
return models.ErrNotAllowedToMerge{ | return models.ErrNotAllowedToMerge{ | ||||
@@ -84,6 +84,7 @@ | |||||
{{- else if .IsPullRequestBroken}}red | {{- else if .IsPullRequestBroken}}red | ||||
{{- else if .IsBlockedByApprovals}}red | {{- else if .IsBlockedByApprovals}}red | ||||
{{- else if .IsBlockedByRejection}}red | {{- else if .IsBlockedByRejection}}red | ||||
{{- else if .IsBlockedByOfficialReviewRequests}}red | |||||
{{- else if .IsBlockedByOutdatedBranch}}red | {{- else if .IsBlockedByOutdatedBranch}}red | ||||
{{- else if .IsBlockedByChangedProtectedFiles}}red | {{- else if .IsBlockedByChangedProtectedFiles}}red | ||||
{{- else if and .EnableStatusCheck (or .RequiredStatusCheckState.IsFailure .RequiredStatusCheckState.IsError)}}red | {{- else if and .EnableStatusCheck (or .RequiredStatusCheckState.IsFailure .RequiredStatusCheckState.IsError)}}red | ||||
@@ -159,6 +160,11 @@ | |||||
<i class="icon icon-octicon">{{svg "octicon-x"}}</i> | <i class="icon icon-octicon">{{svg "octicon-x"}}</i> | ||||
{{$.i18n.Tr "repo.pulls.blocked_by_rejection"}} | {{$.i18n.Tr "repo.pulls.blocked_by_rejection"}} | ||||
</div> | </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}} | {{else if .IsBlockedByOutdatedBranch}} | ||||
<div class="item"> | <div class="item"> | ||||
<i class="icon icon-octicon">{{svg "octicon-x"}}</i> | <i class="icon icon-octicon">{{svg "octicon-x"}}</i> | ||||
@@ -194,7 +200,7 @@ | |||||
{{$.i18n.Tr (printf "repo.signing.wont_sign.%s" .WontSignReason) }} | {{$.i18n.Tr (printf "repo.signing.wont_sign.%s" .WontSignReason) }} | ||||
</div> | </div> | ||||
{{end}} | {{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 and (or $.IsRepoAdmin (not $notAllOverridableChecksOk)) (or (not .AllowMerge) (not .RequireSigned) .WillSign)}} | ||||
{{if $notAllOverridableChecksOk}} | {{if $notAllOverridableChecksOk}} | ||||
<div class="item"> | <div class="item"> | ||||
@@ -384,7 +390,12 @@ | |||||
{{else if .IsBlockedByRejection}} | {{else if .IsBlockedByRejection}} | ||||
<div class="item text red"> | <div class="item text red"> | ||||
{{svg "octicon-x"}} | {{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> | </div> | ||||
{{else if .IsBlockedByOutdatedBranch}} | {{else if .IsBlockedByOutdatedBranch}} | ||||
<div class="item text red"> | <div class="item text red"> | ||||
@@ -213,6 +213,13 @@ | |||||
</div> | </div> | ||||
<div class="field"> | <div class="field"> | ||||
<div class="ui checkbox"> | <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}}> | <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> | <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> | <p class="help">{{.i18n.Tr "repo.settings.dismiss_stale_approvals_desc"}}</p> | ||||
@@ -11326,6 +11326,10 @@ | |||||
}, | }, | ||||
"x-go-name": "ApprovalsWhitelistUsernames" | "x-go-name": "ApprovalsWhitelistUsernames" | ||||
}, | }, | ||||
"block_on_official_review_requests": { | |||||
"type": "boolean", | |||||
"x-go-name": "BlockOnOfficialReviewRequests" | |||||
}, | |||||
"block_on_outdated_branch": { | "block_on_outdated_branch": { | ||||
"type": "boolean", | "type": "boolean", | ||||
"x-go-name": "BlockOnOutdatedBranch" | "x-go-name": "BlockOnOutdatedBranch" | ||||
@@ -11660,6 +11664,10 @@ | |||||
}, | }, | ||||
"x-go-name": "ApprovalsWhitelistUsernames" | "x-go-name": "ApprovalsWhitelistUsernames" | ||||
}, | }, | ||||
"block_on_official_review_requests": { | |||||
"type": "boolean", | |||||
"x-go-name": "BlockOnOfficialReviewRequests" | |||||
}, | |||||
"block_on_outdated_branch": { | "block_on_outdated_branch": { | ||||
"type": "boolean", | "type": "boolean", | ||||
"x-go-name": "BlockOnOutdatedBranch" | "x-go-name": "BlockOnOutdatedBranch" | ||||
@@ -12605,6 +12613,10 @@ | |||||
}, | }, | ||||
"x-go-name": "ApprovalsWhitelistUsernames" | "x-go-name": "ApprovalsWhitelistUsernames" | ||||
}, | }, | ||||
"block_on_official_review_requests": { | |||||
"type": "boolean", | |||||
"x-go-name": "BlockOnOfficialReviewRequests" | |||||
}, | |||||
"block_on_outdated_branch": { | "block_on_outdated_branch": { | ||||
"type": "boolean", | "type": "boolean", | ||||
"x-go-name": "BlockOnOutdatedBranch" | "x-go-name": "BlockOnOutdatedBranch" | ||||