Skip to content

Commit 39ba543

Browse files
committed
Add block on pending codeowner reviews branch protection
1 parent 3763c2a commit 39ba543

File tree

15 files changed

+213
-1
lines changed

15 files changed

+213
-1
lines changed

models/git/protected_branch.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ type ProtectedBranch struct {
5858
RequiredApprovals int64 `xorm:"NOT NULL DEFAULT 0"`
5959
BlockOnRejectedReviews bool `xorm:"NOT NULL DEFAULT false"`
6060
BlockOnOfficialReviewRequests bool `xorm:"NOT NULL DEFAULT false"`
61+
BlockOnCodeownerReviews bool `xorm:"NOT NULL DEFAULT false"`
6162
BlockOnOutdatedBranch bool `xorm:"NOT NULL DEFAULT false"`
6263
DismissStaleApprovals bool `xorm:"NOT NULL DEFAULT false"`
6364
IgnoreStaleApprovals bool `xorm:"NOT NULL DEFAULT false"`

models/migrations/migrations.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"code.gitea.io/gitea/models/migrations/v1_22"
2525
"code.gitea.io/gitea/models/migrations/v1_23"
2626
"code.gitea.io/gitea/models/migrations/v1_24"
27+
"code.gitea.io/gitea/models/migrations/v1_25"
2728
"code.gitea.io/gitea/models/migrations/v1_6"
2829
"code.gitea.io/gitea/models/migrations/v1_7"
2930
"code.gitea.io/gitea/models/migrations/v1_8"
@@ -382,6 +383,10 @@ func prepareMigrationTasks() []*migration {
382383
newMigration(318, "Add anonymous_access_mode for repo_unit", v1_24.AddRepoUnitAnonymousAccessMode),
383384
newMigration(319, "Add ExclusiveOrder to Label table", v1_24.AddExclusiveOrderColumnToLabelTable),
384385
newMigration(320, "Migrate two_factor_policy to login_source table", v1_24.MigrateSkipTwoFactor),
386+
387+
// Gitea 1.24.0 ends at migration ID number 320 (database version 321)
388+
389+
newMigration(321, "Add block on codeowner reviews branch protection", v1_25.AddBlockOnCodeownerReviews),
385390
}
386391
return preparedMigrations
387392
}

models/migrations/v1_25/v321.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_25
5+
6+
import (
7+
"xorm.io/xorm"
8+
)
9+
10+
func AddBlockOnCodeownerReviews(x *xorm.Engine) error {
11+
type ProtectedBranch struct {
12+
BlockOnCodeownerReviews bool `xorm:"NOT NULL DEFAULT false"`
13+
}
14+
15+
return x.Sync(new(ProtectedBranch))
16+
}

modules/structs/repo_branch.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type BranchProtection struct {
4747
ApprovalsWhitelistTeams []string `json:"approvals_whitelist_teams"`
4848
BlockOnRejectedReviews bool `json:"block_on_rejected_reviews"`
4949
BlockOnOfficialReviewRequests bool `json:"block_on_official_review_requests"`
50+
BlockOnCodeownerReviews bool `json:"block_on_codeowner_reviews"`
5051
BlockOnOutdatedBranch bool `json:"block_on_outdated_branch"`
5152
DismissStaleApprovals bool `json:"dismiss_stale_approvals"`
5253
IgnoreStaleApprovals bool `json:"ignore_stale_approvals"`
@@ -87,6 +88,7 @@ type CreateBranchProtectionOption struct {
8788
ApprovalsWhitelistTeams []string `json:"approvals_whitelist_teams"`
8889
BlockOnRejectedReviews bool `json:"block_on_rejected_reviews"`
8990
BlockOnOfficialReviewRequests bool `json:"block_on_official_review_requests"`
91+
BlockOnCodeownerReviews bool `json:"block_on_codeowner_reviews"`
9092
BlockOnOutdatedBranch bool `json:"block_on_outdated_branch"`
9193
DismissStaleApprovals bool `json:"dismiss_stale_approvals"`
9294
IgnoreStaleApprovals bool `json:"ignore_stale_approvals"`
@@ -120,6 +122,7 @@ type EditBranchProtectionOption struct {
120122
ApprovalsWhitelistTeams []string `json:"approvals_whitelist_teams"`
121123
BlockOnRejectedReviews *bool `json:"block_on_rejected_reviews"`
122124
BlockOnOfficialReviewRequests *bool `json:"block_on_official_review_requests"`
125+
BlockOnCodeownerReviews *bool `json:"block_on_codeowner_reviews"`
123126
BlockOnOutdatedBranch *bool `json:"block_on_outdated_branch"`
124127
DismissStaleApprovals *bool `json:"dismiss_stale_approvals"`
125128
IgnoreStaleApprovals *bool `json:"ignore_stale_approvals"`

options/locale/locale_en-US.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,6 +1903,7 @@ pulls.required_status_check_administrator = As an administrator, you may still m
19031903
pulls.blocked_by_approvals = "This pull request doesn't have enough required approvals yet. %d of %d official approvals granted."
19041904
pulls.blocked_by_approvals_whitelisted = "This pull request doesn't have enough required approvals yet. %d of %d approvals granted from users or teams on the allowlist."
19051905
pulls.blocked_by_rejection = "This pull request has changes requested by an official reviewer."
1906+
pulls.blocked_by_codeowners = "This pull request is missing approval from one or more code owners."
19061907
pulls.blocked_by_official_review_requests = "This pull request has official review requests."
19071908
pulls.blocked_by_outdated_branch = "This pull request is blocked because it's outdated."
19081909
pulls.blocked_by_changed_protected_files_1= "This pull request is blocked because it changes a protected file:"
@@ -2538,6 +2539,8 @@ settings.block_rejected_reviews = Block merge on rejected reviews
25382539
settings.block_rejected_reviews_desc = Merging will not be possible when changes are requested by official reviewers, even if there are enough approvals.
25392540
settings.block_on_official_review_requests = Block merge on official review requests
25402541
settings.block_on_official_review_requests_desc = Merging will not be possible when it has official review requests, even if there are enough approvals.
2542+
settings.block_on_codeowner_reviews = Require approval from code owners
2543+
settings.block_on_codeowner_reviews_desc = Merging will only be possible if at least one code owner per code owner rule has given an approving review.
25412544
settings.block_outdated_branch = Block merge if pull request is outdated
25422545
settings.block_outdated_branch_desc = Merging will not be possible when head branch is behind base branch.
25432546
settings.block_admin_merge_override = Administrators must follow branch protection rules

routers/api/v1/repo/branch.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,10 @@ func EditBranchProtection(ctx *context.APIContext) {
855855
protectBranch.BlockOnOfficialReviewRequests = *form.BlockOnOfficialReviewRequests
856856
}
857857

858+
if form.BlockOnCodeownerReviews != nil {
859+
protectBranch.BlockOnCodeownerReviews = *form.BlockOnCodeownerReviews
860+
}
861+
858862
if form.DismissStaleApprovals != nil {
859863
protectBranch.DismissStaleApprovals = *form.DismissStaleApprovals
860864
}

routers/web/repo/issue_view.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,7 @@ func preparePullViewReviewAndMerge(ctx *context.Context, issue *issues_model.Iss
947947
ctx.Data["ProtectedBranch"] = pb
948948
ctx.Data["IsBlockedByApprovals"] = !issues_model.HasEnoughApprovals(ctx, pb, pull)
949949
ctx.Data["IsBlockedByRejection"] = issues_model.MergeBlockedByRejectedReview(ctx, pb, pull)
950+
ctx.Data["IsBlockedByCodeowners"] = !issue_service.HasAllRequiredCodeownerReviews(ctx, pb, pull)
950951
ctx.Data["IsBlockedByOfficialReviewRequests"] = issues_model.MergeBlockedByOfficialReviewRequests(ctx, pb, pull)
951952
ctx.Data["IsBlockedByOutdatedBranch"] = issues_model.MergeBlockedByOutdatedBranch(pb, pull)
952953
ctx.Data["GrantedApprovals"] = issues_model.GetGrantedApprovalsCount(ctx, pb, pull)

routers/web/repo/setting/protected_branch.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
255255
}
256256
protectBranch.BlockOnRejectedReviews = f.BlockOnRejectedReviews
257257
protectBranch.BlockOnOfficialReviewRequests = f.BlockOnOfficialReviewRequests
258+
protectBranch.BlockOnCodeownerReviews = f.BlockOnCodeownerReviews
258259
protectBranch.DismissStaleApprovals = f.DismissStaleApprovals
259260
protectBranch.IgnoreStaleApprovals = f.IgnoreStaleApprovals
260261
protectBranch.RequireSignedCommits = f.RequireSignedCommits

services/convert/convert.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch, repo
189189
ApprovalsWhitelistTeams: approvalsWhitelistTeams,
190190
BlockOnRejectedReviews: bp.BlockOnRejectedReviews,
191191
BlockOnOfficialReviewRequests: bp.BlockOnOfficialReviewRequests,
192+
BlockOnCodeownerReviews: bp.BlockOnCodeownerReviews,
192193
BlockOnOutdatedBranch: bp.BlockOnOutdatedBranch,
193194
DismissStaleApprovals: bp.DismissStaleApprovals,
194195
IgnoreStaleApprovals: bp.IgnoreStaleApprovals,

services/forms/repo_form.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ type ProtectBranchForm struct {
189189
ApprovalsWhitelistTeams string
190190
BlockOnRejectedReviews bool
191191
BlockOnOfficialReviewRequests bool
192+
BlockOnCodeownerReviews bool
192193
BlockOnOutdatedBranch bool
193194
DismissStaleApprovals bool
194195
IgnoreStaleApprovals bool

0 commit comments

Comments
 (0)