Add block on official review requests branch protection (#13705)
Signed-off-by: a1012112796 <1012112796@qq.com> Co-authored-by: Lauris BH <lauris@nix.lv>
This commit is contained in:
		
							parent
							
								
									7ed5bf8cbe
								
							
						
					
					
						commit
						9c26dc1f3a
					
				
					 14 changed files with 228 additions and 141 deletions
				
			
		|  | @ -21,28 +21,29 @@ import ( | ||||||
| 
 | 
 | ||||||
| // ProtectedBranch struct
 | // ProtectedBranch struct
 | ||||||
| type ProtectedBranch struct { | type ProtectedBranch struct { | ||||||
| 	ID                        int64  `xorm:"pk autoincr"` | 	ID                            int64  `xorm:"pk autoincr"` | ||||||
| 	RepoID                    int64  `xorm:"UNIQUE(s)"` | 	RepoID                        int64  `xorm:"UNIQUE(s)"` | ||||||
| 	BranchName                string `xorm:"UNIQUE(s)"` | 	BranchName                    string `xorm:"UNIQUE(s)"` | ||||||
| 	CanPush                   bool   `xorm:"NOT NULL DEFAULT false"` | 	CanPush                       bool   `xorm:"NOT NULL DEFAULT false"` | ||||||
| 	EnableWhitelist           bool | 	EnableWhitelist               bool | ||||||
| 	WhitelistUserIDs          []int64  `xorm:"JSON TEXT"` | 	WhitelistUserIDs              []int64  `xorm:"JSON TEXT"` | ||||||
| 	WhitelistTeamIDs          []int64  `xorm:"JSON TEXT"` | 	WhitelistTeamIDs              []int64  `xorm:"JSON TEXT"` | ||||||
| 	EnableMergeWhitelist      bool     `xorm:"NOT NULL DEFAULT false"` | 	EnableMergeWhitelist          bool     `xorm:"NOT NULL DEFAULT false"` | ||||||
| 	WhitelistDeployKeys       bool     `xorm:"NOT NULL DEFAULT false"` | 	WhitelistDeployKeys           bool     `xorm:"NOT NULL DEFAULT false"` | ||||||
| 	MergeWhitelistUserIDs     []int64  `xorm:"JSON TEXT"` | 	MergeWhitelistUserIDs         []int64  `xorm:"JSON TEXT"` | ||||||
| 	MergeWhitelistTeamIDs     []int64  `xorm:"JSON TEXT"` | 	MergeWhitelistTeamIDs         []int64  `xorm:"JSON TEXT"` | ||||||
| 	EnableStatusCheck         bool     `xorm:"NOT NULL DEFAULT false"` | 	EnableStatusCheck             bool     `xorm:"NOT NULL DEFAULT false"` | ||||||
| 	StatusCheckContexts       []string `xorm:"JSON TEXT"` | 	StatusCheckContexts           []string `xorm:"JSON TEXT"` | ||||||
| 	EnableApprovalsWhitelist  bool     `xorm:"NOT NULL DEFAULT false"` | 	EnableApprovalsWhitelist      bool     `xorm:"NOT NULL DEFAULT false"` | ||||||
| 	ApprovalsWhitelistUserIDs []int64  `xorm:"JSON TEXT"` | 	ApprovalsWhitelistUserIDs     []int64  `xorm:"JSON TEXT"` | ||||||
| 	ApprovalsWhitelistTeamIDs []int64  `xorm:"JSON TEXT"` | 	ApprovalsWhitelistTeamIDs     []int64  `xorm:"JSON TEXT"` | ||||||
| 	RequiredApprovals         int64    `xorm:"NOT NULL DEFAULT 0"` | 	RequiredApprovals             int64    `xorm:"NOT NULL DEFAULT 0"` | ||||||
| 	BlockOnRejectedReviews    bool     `xorm:"NOT NULL DEFAULT false"` | 	BlockOnRejectedReviews        bool     `xorm:"NOT NULL DEFAULT false"` | ||||||
| 	BlockOnOutdatedBranch     bool     `xorm:"NOT NULL DEFAULT false"` | 	BlockOnOfficialReviewRequests bool     `xorm:"NOT NULL DEFAULT false"` | ||||||
| 	DismissStaleApprovals     bool     `xorm:"NOT NULL DEFAULT false"` | 	BlockOnOutdatedBranch         bool     `xorm:"NOT NULL DEFAULT false"` | ||||||
| 	RequireSignedCommits      bool     `xorm:"NOT NULL DEFAULT false"` | 	DismissStaleApprovals         bool     `xorm:"NOT NULL DEFAULT false"` | ||||||
| 	ProtectedFilePatterns     string   `xorm:"TEXT"` | 	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
 | ||||||
|  |  | ||||||
							
								
								
									
										17
									
								
								models/migrations/v160.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								models/migrations/v160.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -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 | 	Protected                     bool | ||||||
| 	EnablePush               string | 	EnablePush                    string | ||||||
| 	WhitelistUsers           string | 	WhitelistUsers                string | ||||||
| 	WhitelistTeams           string | 	WhitelistTeams                string | ||||||
| 	WhitelistDeployKeys      bool | 	WhitelistDeployKeys           bool | ||||||
| 	EnableMergeWhitelist     bool | 	EnableMergeWhitelist          bool | ||||||
| 	MergeWhitelistUsers      string | 	MergeWhitelistUsers           string | ||||||
| 	MergeWhitelistTeams      string | 	MergeWhitelistTeams           string | ||||||
| 	EnableStatusCheck        bool `xorm:"NOT NULL DEFAULT false"` | 	EnableStatusCheck             bool | ||||||
| 	StatusCheckContexts      []string | 	StatusCheckContexts           []string | ||||||
| 	RequiredApprovals        int64 | 	RequiredApprovals             int64 | ||||||
| 	EnableApprovalsWhitelist bool | 	EnableApprovalsWhitelist      bool | ||||||
| 	ApprovalsWhitelistUsers  string | 	ApprovalsWhitelistUsers       string | ||||||
| 	ApprovalsWhitelistTeams  string | 	ApprovalsWhitelistTeams       string | ||||||
| 	BlockOnRejectedReviews   bool | 	BlockOnRejectedReviews        bool | ||||||
| 	BlockOnOutdatedBranch    bool | 	BlockOnOfficialReviewRequests bool | ||||||
| 	DismissStaleApprovals    bool | 	BlockOnOutdatedBranch         bool | ||||||
| 	RequireSignedCommits     bool | 	DismissStaleApprovals         bool | ||||||
| 	ProtectedFilePatterns    string | 	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, | 		BranchName:                    bp.BranchName, | ||||||
| 		EnablePush:                  bp.CanPush, | 		EnablePush:                    bp.CanPush, | ||||||
| 		EnablePushWhitelist:         bp.EnableWhitelist, | 		EnablePushWhitelist:           bp.EnableWhitelist, | ||||||
| 		PushWhitelistUsernames:      pushWhitelistUsernames, | 		PushWhitelistUsernames:        pushWhitelistUsernames, | ||||||
| 		PushWhitelistTeams:          pushWhitelistTeams, | 		PushWhitelistTeams:            pushWhitelistTeams, | ||||||
| 		PushWhitelistDeployKeys:     bp.WhitelistDeployKeys, | 		PushWhitelistDeployKeys:       bp.WhitelistDeployKeys, | ||||||
| 		EnableMergeWhitelist:        bp.EnableMergeWhitelist, | 		EnableMergeWhitelist:          bp.EnableMergeWhitelist, | ||||||
| 		MergeWhitelistUsernames:     mergeWhitelistUsernames, | 		MergeWhitelistUsernames:       mergeWhitelistUsernames, | ||||||
| 		MergeWhitelistTeams:         mergeWhitelistTeams, | 		MergeWhitelistTeams:           mergeWhitelistTeams, | ||||||
| 		EnableStatusCheck:           bp.EnableStatusCheck, | 		EnableStatusCheck:             bp.EnableStatusCheck, | ||||||
| 		StatusCheckContexts:         bp.StatusCheckContexts, | 		StatusCheckContexts:           bp.StatusCheckContexts, | ||||||
| 		RequiredApprovals:           bp.RequiredApprovals, | 		RequiredApprovals:             bp.RequiredApprovals, | ||||||
| 		EnableApprovalsWhitelist:    bp.EnableApprovalsWhitelist, | 		EnableApprovalsWhitelist:      bp.EnableApprovalsWhitelist, | ||||||
| 		ApprovalsWhitelistUsernames: approvalsWhitelistUsernames, | 		ApprovalsWhitelistUsernames:   approvalsWhitelistUsernames, | ||||||
| 		ApprovalsWhitelistTeams:     approvalsWhitelistTeams, | 		ApprovalsWhitelistTeams:       approvalsWhitelistTeams, | ||||||
| 		BlockOnRejectedReviews:      bp.BlockOnRejectedReviews, | 		BlockOnRejectedReviews:        bp.BlockOnRejectedReviews, | ||||||
| 		BlockOnOutdatedBranch:       bp.BlockOnOutdatedBranch, | 		BlockOnOfficialReviewRequests: bp.BlockOnOfficialReviewRequests, | ||||||
| 		DismissStaleApprovals:       bp.DismissStaleApprovals, | 		BlockOnOutdatedBranch:         bp.BlockOnOutdatedBranch, | ||||||
| 		RequireSignedCommits:        bp.RequireSignedCommits, | 		DismissStaleApprovals:         bp.DismissStaleApprovals, | ||||||
| 		ProtectedFilePatterns:       bp.ProtectedFilePatterns, | 		RequireSignedCommits:          bp.RequireSignedCommits, | ||||||
| 		Created:                     bp.CreatedUnix.AsTime(), | 		ProtectedFilePatterns:         bp.ProtectedFilePatterns, | ||||||
| 		Updated:                     bp.UpdatedUnix.AsTime(), | 		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"` | 	BranchName                    string   `json:"branch_name"` | ||||||
| 	EnablePush                  bool     `json:"enable_push"` | 	EnablePush                    bool     `json:"enable_push"` | ||||||
| 	EnablePushWhitelist         bool     `json:"enable_push_whitelist"` | 	EnablePushWhitelist           bool     `json:"enable_push_whitelist"` | ||||||
| 	PushWhitelistUsernames      []string `json:"push_whitelist_usernames"` | 	PushWhitelistUsernames        []string `json:"push_whitelist_usernames"` | ||||||
| 	PushWhitelistTeams          []string `json:"push_whitelist_teams"` | 	PushWhitelistTeams            []string `json:"push_whitelist_teams"` | ||||||
| 	PushWhitelistDeployKeys     bool     `json:"push_whitelist_deploy_keys"` | 	PushWhitelistDeployKeys       bool     `json:"push_whitelist_deploy_keys"` | ||||||
| 	EnableMergeWhitelist        bool     `json:"enable_merge_whitelist"` | 	EnableMergeWhitelist          bool     `json:"enable_merge_whitelist"` | ||||||
| 	MergeWhitelistUsernames     []string `json:"merge_whitelist_usernames"` | 	MergeWhitelistUsernames       []string `json:"merge_whitelist_usernames"` | ||||||
| 	MergeWhitelistTeams         []string `json:"merge_whitelist_teams"` | 	MergeWhitelistTeams           []string `json:"merge_whitelist_teams"` | ||||||
| 	EnableStatusCheck           bool     `json:"enable_status_check"` | 	EnableStatusCheck             bool     `json:"enable_status_check"` | ||||||
| 	StatusCheckContexts         []string `json:"status_check_contexts"` | 	StatusCheckContexts           []string `json:"status_check_contexts"` | ||||||
| 	RequiredApprovals           int64    `json:"required_approvals"` | 	RequiredApprovals             int64    `json:"required_approvals"` | ||||||
| 	EnableApprovalsWhitelist    bool     `json:"enable_approvals_whitelist"` | 	EnableApprovalsWhitelist      bool     `json:"enable_approvals_whitelist"` | ||||||
| 	ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"` | 	ApprovalsWhitelistUsernames   []string `json:"approvals_whitelist_username"` | ||||||
| 	ApprovalsWhitelistTeams     []string `json:"approvals_whitelist_teams"` | 	ApprovalsWhitelistTeams       []string `json:"approvals_whitelist_teams"` | ||||||
| 	BlockOnRejectedReviews      bool     `json:"block_on_rejected_reviews"` | 	BlockOnRejectedReviews        bool     `json:"block_on_rejected_reviews"` | ||||||
| 	BlockOnOutdatedBranch       bool     `json:"block_on_outdated_branch"` | 	BlockOnOfficialReviewRequests bool     `json:"block_on_official_review_requests"` | ||||||
| 	DismissStaleApprovals       bool     `json:"dismiss_stale_approvals"` | 	BlockOnOutdatedBranch         bool     `json:"block_on_outdated_branch"` | ||||||
| 	RequireSignedCommits        bool     `json:"require_signed_commits"` | 	DismissStaleApprovals         bool     `json:"dismiss_stale_approvals"` | ||||||
| 	ProtectedFilePatterns       string   `json:"protected_file_patterns"` | 	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"` | 	BranchName                    string   `json:"branch_name"` | ||||||
| 	EnablePush                  bool     `json:"enable_push"` | 	EnablePush                    bool     `json:"enable_push"` | ||||||
| 	EnablePushWhitelist         bool     `json:"enable_push_whitelist"` | 	EnablePushWhitelist           bool     `json:"enable_push_whitelist"` | ||||||
| 	PushWhitelistUsernames      []string `json:"push_whitelist_usernames"` | 	PushWhitelistUsernames        []string `json:"push_whitelist_usernames"` | ||||||
| 	PushWhitelistTeams          []string `json:"push_whitelist_teams"` | 	PushWhitelistTeams            []string `json:"push_whitelist_teams"` | ||||||
| 	PushWhitelistDeployKeys     bool     `json:"push_whitelist_deploy_keys"` | 	PushWhitelistDeployKeys       bool     `json:"push_whitelist_deploy_keys"` | ||||||
| 	EnableMergeWhitelist        bool     `json:"enable_merge_whitelist"` | 	EnableMergeWhitelist          bool     `json:"enable_merge_whitelist"` | ||||||
| 	MergeWhitelistUsernames     []string `json:"merge_whitelist_usernames"` | 	MergeWhitelistUsernames       []string `json:"merge_whitelist_usernames"` | ||||||
| 	MergeWhitelistTeams         []string `json:"merge_whitelist_teams"` | 	MergeWhitelistTeams           []string `json:"merge_whitelist_teams"` | ||||||
| 	EnableStatusCheck           bool     `json:"enable_status_check"` | 	EnableStatusCheck             bool     `json:"enable_status_check"` | ||||||
| 	StatusCheckContexts         []string `json:"status_check_contexts"` | 	StatusCheckContexts           []string `json:"status_check_contexts"` | ||||||
| 	RequiredApprovals           int64    `json:"required_approvals"` | 	RequiredApprovals             int64    `json:"required_approvals"` | ||||||
| 	EnableApprovalsWhitelist    bool     `json:"enable_approvals_whitelist"` | 	EnableApprovalsWhitelist      bool     `json:"enable_approvals_whitelist"` | ||||||
| 	ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"` | 	ApprovalsWhitelistUsernames   []string `json:"approvals_whitelist_username"` | ||||||
| 	ApprovalsWhitelistTeams     []string `json:"approvals_whitelist_teams"` | 	ApprovalsWhitelistTeams       []string `json:"approvals_whitelist_teams"` | ||||||
| 	BlockOnRejectedReviews      bool     `json:"block_on_rejected_reviews"` | 	BlockOnRejectedReviews        bool     `json:"block_on_rejected_reviews"` | ||||||
| 	BlockOnOutdatedBranch       bool     `json:"block_on_outdated_branch"` | 	BlockOnOfficialReviewRequests bool     `json:"block_on_official_review_requests"` | ||||||
| 	DismissStaleApprovals       bool     `json:"dismiss_stale_approvals"` | 	BlockOnOutdatedBranch         bool     `json:"block_on_outdated_branch"` | ||||||
| 	RequireSignedCommits        bool     `json:"require_signed_commits"` | 	DismissStaleApprovals         bool     `json:"dismiss_stale_approvals"` | ||||||
| 	ProtectedFilePatterns       string   `json:"protected_file_patterns"` | 	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"` | 	EnablePush                    *bool    `json:"enable_push"` | ||||||
| 	EnablePushWhitelist         *bool    `json:"enable_push_whitelist"` | 	EnablePushWhitelist           *bool    `json:"enable_push_whitelist"` | ||||||
| 	PushWhitelistUsernames      []string `json:"push_whitelist_usernames"` | 	PushWhitelistUsernames        []string `json:"push_whitelist_usernames"` | ||||||
| 	PushWhitelistTeams          []string `json:"push_whitelist_teams"` | 	PushWhitelistTeams            []string `json:"push_whitelist_teams"` | ||||||
| 	PushWhitelistDeployKeys     *bool    `json:"push_whitelist_deploy_keys"` | 	PushWhitelistDeployKeys       *bool    `json:"push_whitelist_deploy_keys"` | ||||||
| 	EnableMergeWhitelist        *bool    `json:"enable_merge_whitelist"` | 	EnableMergeWhitelist          *bool    `json:"enable_merge_whitelist"` | ||||||
| 	MergeWhitelistUsernames     []string `json:"merge_whitelist_usernames"` | 	MergeWhitelistUsernames       []string `json:"merge_whitelist_usernames"` | ||||||
| 	MergeWhitelistTeams         []string `json:"merge_whitelist_teams"` | 	MergeWhitelistTeams           []string `json:"merge_whitelist_teams"` | ||||||
| 	EnableStatusCheck           *bool    `json:"enable_status_check"` | 	EnableStatusCheck             *bool    `json:"enable_status_check"` | ||||||
| 	StatusCheckContexts         []string `json:"status_check_contexts"` | 	StatusCheckContexts           []string `json:"status_check_contexts"` | ||||||
| 	RequiredApprovals           *int64   `json:"required_approvals"` | 	RequiredApprovals             *int64   `json:"required_approvals"` | ||||||
| 	EnableApprovalsWhitelist    *bool    `json:"enable_approvals_whitelist"` | 	EnableApprovalsWhitelist      *bool    `json:"enable_approvals_whitelist"` | ||||||
| 	ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"` | 	ApprovalsWhitelistUsernames   []string `json:"approvals_whitelist_username"` | ||||||
| 	ApprovalsWhitelistTeams     []string `json:"approvals_whitelist_teams"` | 	ApprovalsWhitelistTeams       []string `json:"approvals_whitelist_teams"` | ||||||
| 	BlockOnRejectedReviews      *bool    `json:"block_on_rejected_reviews"` | 	BlockOnRejectedReviews        *bool    `json:"block_on_rejected_reviews"` | ||||||
| 	BlockOnOutdatedBranch       *bool    `json:"block_on_outdated_branch"` | 	BlockOnOfficialReviewRequests *bool    `json:"block_on_official_review_requests"` | ||||||
| 	DismissStaleApprovals       *bool    `json:"dismiss_stale_approvals"` | 	BlockOnOutdatedBranch         *bool    `json:"block_on_outdated_branch"` | ||||||
| 	RequireSignedCommits        *bool    `json:"require_signed_commits"` | 	DismissStaleApprovals         *bool    `json:"dismiss_stale_approvals"` | ||||||
| 	ProtectedFilePatterns       *string  `json:"protected_file_patterns"` | 	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, | 		RepoID:                        ctx.Repo.Repository.ID, | ||||||
| 		BranchName:               form.BranchName, | 		BranchName:                    form.BranchName, | ||||||
| 		CanPush:                  form.EnablePush, | 		CanPush:                       form.EnablePush, | ||||||
| 		EnableWhitelist:          form.EnablePush && form.EnablePushWhitelist, | 		EnableWhitelist:               form.EnablePush && form.EnablePushWhitelist, | ||||||
| 		EnableMergeWhitelist:     form.EnableMergeWhitelist, | 		EnableMergeWhitelist:          form.EnableMergeWhitelist, | ||||||
| 		WhitelistDeployKeys:      form.EnablePush && form.EnablePushWhitelist && form.PushWhitelistDeployKeys, | 		WhitelistDeployKeys:           form.EnablePush && form.EnablePushWhitelist && form.PushWhitelistDeployKeys, | ||||||
| 		EnableStatusCheck:        form.EnableStatusCheck, | 		EnableStatusCheck:             form.EnableStatusCheck, | ||||||
| 		StatusCheckContexts:      form.StatusCheckContexts, | 		StatusCheckContexts:           form.StatusCheckContexts, | ||||||
| 		EnableApprovalsWhitelist: form.EnableApprovalsWhitelist, | 		EnableApprovalsWhitelist:      form.EnableApprovalsWhitelist, | ||||||
| 		RequiredApprovals:        requiredApprovals, | 		RequiredApprovals:             requiredApprovals, | ||||||
| 		BlockOnRejectedReviews:   form.BlockOnRejectedReviews, | 		BlockOnRejectedReviews:        form.BlockOnRejectedReviews, | ||||||
| 		DismissStaleApprovals:    form.DismissStaleApprovals, | 		BlockOnOfficialReviewRequests: form.BlockOnOfficialReviewRequests, | ||||||
| 		RequireSignedCommits:     form.RequireSignedCommits, | 		DismissStaleApprovals:         form.DismissStaleApprovals, | ||||||
| 		ProtectedFilePatterns:    form.ProtectedFilePatterns, | 		RequireSignedCommits:          form.RequireSignedCommits, | ||||||
| 		BlockOnOutdatedBranch:    form.BlockOnOutdatedBranch, | 		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"> | ||||||
|  |  | ||||||
|  | @ -211,6 +211,13 @@ | ||||||
| 							<p class="help">{{.i18n.Tr "repo.settings.block_rejected_reviews_desc"}}</p> | 							<p class="help">{{.i18n.Tr "repo.settings.block_rejected_reviews_desc"}}</p> | ||||||
| 						</div> | 						</div> | ||||||
| 					</div> | 					</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="field"> | ||||||
| 						<div class="ui checkbox"> | 						<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}}> | ||||||
|  |  | ||||||
|  | @ -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" | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue