Skip to content

Commit 31a9619

Browse files
Merge branch 'main' into pacman-packages
2 parents e21ef0d + 264f74c commit 31a9619

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+742
-612
lines changed

models/git/protected_branch.go

Lines changed: 93 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ type ProtectedBranch struct {
4444
WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`
4545
MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
4646
MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
47+
CanForcePush bool `xorm:"NOT NULL DEFAULT false"`
48+
EnableForcePushAllowlist bool `xorm:"NOT NULL DEFAULT false"`
49+
ForcePushAllowlistUserIDs []int64 `xorm:"JSON TEXT"`
50+
ForcePushAllowlistTeamIDs []int64 `xorm:"JSON TEXT"`
51+
ForcePushAllowlistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`
4752
EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"`
4853
StatusCheckContexts []string `xorm:"JSON TEXT"`
4954
EnableApprovalsWhitelist bool `xorm:"NOT NULL DEFAULT false"`
@@ -143,6 +148,33 @@ func (protectBranch *ProtectedBranch) CanUserPush(ctx context.Context, user *use
143148
return in
144149
}
145150

151+
// CanUserForcePush returns if some user could force push to this protected branch
152+
// Since force-push extends normal push, we also check if user has regular push access
153+
func (protectBranch *ProtectedBranch) CanUserForcePush(ctx context.Context, user *user_model.User) bool {
154+
if !protectBranch.CanForcePush {
155+
return false
156+
}
157+
158+
if !protectBranch.EnableForcePushAllowlist {
159+
return protectBranch.CanUserPush(ctx, user)
160+
}
161+
162+
if slices.Contains(protectBranch.ForcePushAllowlistUserIDs, user.ID) {
163+
return protectBranch.CanUserPush(ctx, user)
164+
}
165+
166+
if len(protectBranch.ForcePushAllowlistTeamIDs) == 0 {
167+
return false
168+
}
169+
170+
in, err := organization.IsUserInTeams(ctx, user.ID, protectBranch.ForcePushAllowlistTeamIDs)
171+
if err != nil {
172+
log.Error("IsUserInTeams: %v", err)
173+
return false
174+
}
175+
return in && protectBranch.CanUserPush(ctx, user)
176+
}
177+
146178
// IsUserMergeWhitelisted checks if some user is whitelisted to merge to this branch
147179
func IsUserMergeWhitelisted(ctx context.Context, protectBranch *ProtectedBranch, userID int64, permissionInRepo access_model.Permission) bool {
148180
if !protectBranch.EnableMergeWhitelist {
@@ -301,6 +333,9 @@ type WhitelistOptions struct {
301333
UserIDs []int64
302334
TeamIDs []int64
303335

336+
ForcePushUserIDs []int64
337+
ForcePushTeamIDs []int64
338+
304339
MergeUserIDs []int64
305340
MergeTeamIDs []int64
306341

@@ -328,6 +363,12 @@ func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, prote
328363
}
329364
protectBranch.WhitelistUserIDs = whitelist
330365

366+
whitelist, err = updateUserWhitelist(ctx, repo, protectBranch.ForcePushAllowlistUserIDs, opts.ForcePushUserIDs)
367+
if err != nil {
368+
return err
369+
}
370+
protectBranch.ForcePushAllowlistUserIDs = whitelist
371+
331372
whitelist, err = updateUserWhitelist(ctx, repo, protectBranch.MergeWhitelistUserIDs, opts.MergeUserIDs)
332373
if err != nil {
333374
return err
@@ -347,6 +388,12 @@ func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, prote
347388
}
348389
protectBranch.WhitelistTeamIDs = whitelist
349390

391+
whitelist, err = updateTeamWhitelist(ctx, repo, protectBranch.ForcePushAllowlistTeamIDs, opts.ForcePushTeamIDs)
392+
if err != nil {
393+
return err
394+
}
395+
protectBranch.ForcePushAllowlistTeamIDs = whitelist
396+
350397
whitelist, err = updateTeamWhitelist(ctx, repo, protectBranch.MergeWhitelistTeamIDs, opts.MergeTeamIDs)
351398
if err != nil {
352399
return err
@@ -468,43 +515,58 @@ func DeleteProtectedBranch(ctx context.Context, repo *repo_model.Repository, id
468515
return nil
469516
}
470517

471-
// RemoveUserIDFromProtectedBranch remove all user ids from protected branch options
472-
func RemoveUserIDFromProtectedBranch(ctx context.Context, p *ProtectedBranch, userID int64) error {
473-
lenIDs, lenApprovalIDs, lenMergeIDs := len(p.WhitelistUserIDs), len(p.ApprovalsWhitelistUserIDs), len(p.MergeWhitelistUserIDs)
474-
p.WhitelistUserIDs = util.SliceRemoveAll(p.WhitelistUserIDs, userID)
475-
p.ApprovalsWhitelistUserIDs = util.SliceRemoveAll(p.ApprovalsWhitelistUserIDs, userID)
476-
p.MergeWhitelistUserIDs = util.SliceRemoveAll(p.MergeWhitelistUserIDs, userID)
477-
478-
if lenIDs != len(p.WhitelistUserIDs) || lenApprovalIDs != len(p.ApprovalsWhitelistUserIDs) ||
479-
lenMergeIDs != len(p.MergeWhitelistUserIDs) {
480-
if _, err := db.GetEngine(ctx).ID(p.ID).Cols(
481-
"whitelist_user_i_ds",
482-
"merge_whitelist_user_i_ds",
483-
"approvals_whitelist_user_i_ds",
484-
).Update(p); err != nil {
518+
// removeIDsFromProtectedBranch is a helper function to remove IDs from protected branch options
519+
func removeIDsFromProtectedBranch(ctx context.Context, p *ProtectedBranch, userID, teamID int64, columnNames []string) error {
520+
lenUserIDs, lenForcePushIDs, lenApprovalIDs, lenMergeIDs := len(p.WhitelistUserIDs), len(p.ForcePushAllowlistUserIDs), len(p.ApprovalsWhitelistUserIDs), len(p.MergeWhitelistUserIDs)
521+
lenTeamIDs, lenForcePushTeamIDs, lenApprovalTeamIDs, lenMergeTeamIDs := len(p.WhitelistTeamIDs), len(p.ForcePushAllowlistTeamIDs), len(p.ApprovalsWhitelistTeamIDs), len(p.MergeWhitelistTeamIDs)
522+
523+
if userID > 0 {
524+
p.WhitelistUserIDs = util.SliceRemoveAll(p.WhitelistUserIDs, userID)
525+
p.ForcePushAllowlistUserIDs = util.SliceRemoveAll(p.ForcePushAllowlistUserIDs, userID)
526+
p.ApprovalsWhitelistUserIDs = util.SliceRemoveAll(p.ApprovalsWhitelistUserIDs, userID)
527+
p.MergeWhitelistUserIDs = util.SliceRemoveAll(p.MergeWhitelistUserIDs, userID)
528+
}
529+
530+
if teamID > 0 {
531+
p.WhitelistTeamIDs = util.SliceRemoveAll(p.WhitelistTeamIDs, teamID)
532+
p.ForcePushAllowlistTeamIDs = util.SliceRemoveAll(p.ForcePushAllowlistTeamIDs, teamID)
533+
p.ApprovalsWhitelistTeamIDs = util.SliceRemoveAll(p.ApprovalsWhitelistTeamIDs, teamID)
534+
p.MergeWhitelistTeamIDs = util.SliceRemoveAll(p.MergeWhitelistTeamIDs, teamID)
535+
}
536+
537+
if (lenUserIDs != len(p.WhitelistUserIDs) ||
538+
lenForcePushIDs != len(p.ForcePushAllowlistUserIDs) ||
539+
lenApprovalIDs != len(p.ApprovalsWhitelistUserIDs) ||
540+
lenMergeIDs != len(p.MergeWhitelistUserIDs)) ||
541+
(lenTeamIDs != len(p.WhitelistTeamIDs) ||
542+
lenForcePushTeamIDs != len(p.ForcePushAllowlistTeamIDs) ||
543+
lenApprovalTeamIDs != len(p.ApprovalsWhitelistTeamIDs) ||
544+
lenMergeTeamIDs != len(p.MergeWhitelistTeamIDs)) {
545+
if _, err := db.GetEngine(ctx).ID(p.ID).Cols(columnNames...).Update(p); err != nil {
485546
return fmt.Errorf("updateProtectedBranches: %v", err)
486547
}
487548
}
488549
return nil
489550
}
490551

491-
// RemoveTeamIDFromProtectedBranch remove all team ids from protected branch options
552+
// RemoveUserIDFromProtectedBranch removes all user ids from protected branch options
553+
func RemoveUserIDFromProtectedBranch(ctx context.Context, p *ProtectedBranch, userID int64) error {
554+
columnNames := []string{
555+
"whitelist_user_i_ds",
556+
"force_push_allowlist_user_i_ds",
557+
"merge_whitelist_user_i_ds",
558+
"approvals_whitelist_user_i_ds",
559+
}
560+
return removeIDsFromProtectedBranch(ctx, p, userID, 0, columnNames)
561+
}
562+
563+
// RemoveTeamIDFromProtectedBranch removes all team ids from protected branch options
492564
func RemoveTeamIDFromProtectedBranch(ctx context.Context, p *ProtectedBranch, teamID int64) error {
493-
lenIDs, lenApprovalIDs, lenMergeIDs := len(p.WhitelistTeamIDs), len(p.ApprovalsWhitelistTeamIDs), len(p.MergeWhitelistTeamIDs)
494-
p.WhitelistTeamIDs = util.SliceRemoveAll(p.WhitelistTeamIDs, teamID)
495-
p.ApprovalsWhitelistTeamIDs = util.SliceRemoveAll(p.ApprovalsWhitelistTeamIDs, teamID)
496-
p.MergeWhitelistTeamIDs = util.SliceRemoveAll(p.MergeWhitelistTeamIDs, teamID)
497-
498-
if lenIDs != len(p.WhitelistTeamIDs) ||
499-
lenApprovalIDs != len(p.ApprovalsWhitelistTeamIDs) ||
500-
lenMergeIDs != len(p.MergeWhitelistTeamIDs) {
501-
if _, err := db.GetEngine(ctx).ID(p.ID).Cols(
502-
"whitelist_team_i_ds",
503-
"merge_whitelist_team_i_ds",
504-
"approvals_whitelist_team_i_ds",
505-
).Update(p); err != nil {
506-
return fmt.Errorf("updateProtectedBranches: %v", err)
507-
}
565+
columnNames := []string{
566+
"whitelist_team_i_ds",
567+
"force_push_allowlist_team_i_ds",
568+
"merge_whitelist_team_i_ds",
569+
"approvals_whitelist_team_i_ds",
508570
}
509-
return nil
571+
return removeIDsFromProtectedBranch(ctx, p, 0, teamID, columnNames)
510572
}

models/migrations/migrations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,8 @@ var migrations = []Migration{
591591

592592
// v299 -> v300
593593
NewMigration("Add content version to issue and comment table", v1_23.AddContentVersionToIssueAndComment),
594+
// v300 -> v301
595+
NewMigration("Add force-push branch protection support", v1_23.AddForcePushBranchProtection),
594596
}
595597

596598
// GetCurrentDBVersion returns the current db version

models/migrations/v1_23/v300.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2024 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_23 //nolint
5+
6+
import "xorm.io/xorm"
7+
8+
func AddForcePushBranchProtection(x *xorm.Engine) error {
9+
type ProtectedBranch struct {
10+
CanForcePush bool `xorm:"NOT NULL DEFAULT false"`
11+
EnableForcePushAllowlist bool `xorm:"NOT NULL DEFAULT false"`
12+
ForcePushAllowlistUserIDs []int64 `xorm:"JSON TEXT"`
13+
ForcePushAllowlistTeamIDs []int64 `xorm:"JSON TEXT"`
14+
ForcePushAllowlistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`
15+
}
16+
return x.Sync(new(ProtectedBranch))
17+
}

modules/git/repo_index.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,8 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
104104
buffer := new(bytes.Buffer)
105105
for _, file := range filenames {
106106
if file != "" {
107-
buffer.WriteString("0 ")
108-
buffer.WriteString(objectFormat.EmptyObjectID().String())
109-
buffer.WriteByte('\t')
110-
buffer.WriteString(file)
111-
buffer.WriteByte('\000')
107+
// using format: mode SP type SP sha1 TAB path
108+
buffer.WriteString("0 blob " + objectFormat.EmptyObjectID().String() + "\t" + file + "\000")
112109
}
113110
}
114111
return cmd.Run(&RunOpts{
@@ -119,11 +116,33 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
119116
})
120117
}
121118

119+
type IndexObjectInfo struct {
120+
Mode string
121+
Object ObjectID
122+
Filename string
123+
}
124+
125+
// AddObjectsToIndex adds the provided object hashes to the index at the provided filenames
126+
func (repo *Repository) AddObjectsToIndex(objects ...IndexObjectInfo) error {
127+
cmd := NewCommand(repo.Ctx, "update-index", "--add", "--replace", "-z", "--index-info")
128+
stdout := new(bytes.Buffer)
129+
stderr := new(bytes.Buffer)
130+
buffer := new(bytes.Buffer)
131+
for _, object := range objects {
132+
// using format: mode SP type SP sha1 TAB path
133+
buffer.WriteString(object.Mode + " blob " + object.Object.String() + "\t" + object.Filename + "\000")
134+
}
135+
return cmd.Run(&RunOpts{
136+
Dir: repo.Path,
137+
Stdin: bytes.NewReader(buffer.Bytes()),
138+
Stdout: stdout,
139+
Stderr: stderr,
140+
})
141+
}
142+
122143
// AddObjectToIndex adds the provided object hash to the index at the provided filename
123144
func (repo *Repository) AddObjectToIndex(mode string, object ObjectID, filename string) error {
124-
cmd := NewCommand(repo.Ctx, "update-index", "--add", "--replace", "--cacheinfo").AddDynamicArguments(mode, object.String(), filename)
125-
_, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
126-
return err
145+
return repo.AddObjectsToIndex(IndexObjectInfo{Mode: mode, Object: object, Filename: filename})
127146
}
128147

129148
// WriteTree writes the current index as a tree to the object db and returns its hash

modules/structs/repo_branch.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ type BranchProtection struct {
3030
PushWhitelistUsernames []string `json:"push_whitelist_usernames"`
3131
PushWhitelistTeams []string `json:"push_whitelist_teams"`
3232
PushWhitelistDeployKeys bool `json:"push_whitelist_deploy_keys"`
33+
EnableForcePush bool `json:"enable_force_push"`
34+
EnableForcePushAllowlist bool `json:"enable_force_push_allowlist"`
35+
ForcePushAllowlistUsernames []string `json:"force_push_allowlist_usernames"`
36+
ForcePushAllowlistTeams []string `json:"force_push_allowlist_teams"`
37+
ForcePushAllowlistDeployKeys bool `json:"force_push_allowlist_deploy_keys"`
3338
EnableMergeWhitelist bool `json:"enable_merge_whitelist"`
3439
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
3540
MergeWhitelistTeams []string `json:"merge_whitelist_teams"`
@@ -63,6 +68,11 @@ type CreateBranchProtectionOption struct {
6368
PushWhitelistUsernames []string `json:"push_whitelist_usernames"`
6469
PushWhitelistTeams []string `json:"push_whitelist_teams"`
6570
PushWhitelistDeployKeys bool `json:"push_whitelist_deploy_keys"`
71+
EnableForcePush bool `json:"enable_force_push"`
72+
EnableForcePushAllowlist bool `json:"enable_force_push_allowlist"`
73+
ForcePushAllowlistUsernames []string `json:"force_push_allowlist_usernames"`
74+
ForcePushAllowlistTeams []string `json:"force_push_allowlist_teams"`
75+
ForcePushAllowlistDeployKeys bool `json:"force_push_allowlist_deploy_keys"`
6676
EnableMergeWhitelist bool `json:"enable_merge_whitelist"`
6777
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
6878
MergeWhitelistTeams []string `json:"merge_whitelist_teams"`
@@ -89,6 +99,11 @@ type EditBranchProtectionOption struct {
8999
PushWhitelistUsernames []string `json:"push_whitelist_usernames"`
90100
PushWhitelistTeams []string `json:"push_whitelist_teams"`
91101
PushWhitelistDeployKeys *bool `json:"push_whitelist_deploy_keys"`
102+
EnableForcePush *bool `json:"enable_force_push"`
103+
EnableForcePushAllowlist *bool `json:"enable_force_push_allowlist"`
104+
ForcePushAllowlistUsernames []string `json:"force_push_allowlist_usernames"`
105+
ForcePushAllowlistTeams []string `json:"force_push_allowlist_teams"`
106+
ForcePushAllowlistDeployKeys *bool `json:"force_push_allowlist_deploy_keys"`
92107
EnableMergeWhitelist *bool `json:"enable_merge_whitelist"`
93108
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
94109
MergeWhitelistTeams []string `json:"merge_whitelist_teams"`

options/locale/locale_cs-CZ.ini

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -387,16 +387,13 @@ relevant_repositories=Zobrazují se pouze relevantní repositáře, <a href="%s"
387387

388388
[auth]
389389
create_new_account=Registrovat účet
390-
register_helper_msg=Již máte účet? Přihlaste se!
391-
social_register_helper_msg=Již máte účet? Připojte ho!
392390
disable_register_prompt=Registrace jsou vypnuty. Prosíme, kontaktujte správce systému.
393391
disable_register_mail=E-mailové potvrzení o registraci je zakázané.
394392
manual_activation_only=Pro dokončení aktivace kontaktujte správce webu.
395393
remember_me=Pamatovat si toto zařízení
396394
remember_me.compromised=Přihlašovací token již není platný, což může znamenat napadení účtu. Zkontrolujte prosím svůj účet pro neobvyklé aktivity.
397395
forgot_password_title=Zapomenuté heslo
398396
forgot_password=Zapomenuté heslo?
399-
sign_up_now=Potřebujete účet? Zaregistrujte se.
400397
sign_up_successful=Účet byl úspěšně vytvořen. Vítejte!
401398
confirmation_mail_sent_prompt_ex=Nový potvrzovací e-mail byl odeslán na <b>%s</b>. Zkontrolujte prosím svou doručenou poštu během následujících %s a dokončete proces registrace. Pokud je Vaše registrační e-mailová adresa nesprávná, můžete se znovu přihlásit a změnit ji.
402399
must_change_password=Aktualizujte své heslo
@@ -2373,15 +2370,6 @@ settings.protect_enable_push=Povolit nahrávání
23732370
settings.protect_enable_push_desc=Každý, kdo má přístup k zápisu, bude moci nahrávat do této větve (ale ne vynucená nahrávání).
23742371
settings.protect_enable_merge=Povolit sloučení
23752372
settings.protect_enable_merge_desc=Každému, kdo má přístup k zápisu, bude povoleno sloučit pull requesty do této větve.
2376-
settings.protect_whitelist_committers=Povolit nahrání jen vyjmenovaným
2377-
settings.protect_whitelist_committers_desc=Pouze povolení uživatelé budou moci nahrávat do této větve (ale ne vynucení nahrávání).
2378-
settings.protect_whitelist_deploy_keys=Povolit nahrání klíčům pro nasazení s přístupem pro zápis.
2379-
settings.protect_whitelist_users=Povolení uživatelé pro nahrávání:
2380-
settings.protect_whitelist_teams=Povolené týmy pro nahrávání:
2381-
settings.protect_merge_whitelist_committers=Povolit vyjmenovaným slučování
2382-
settings.protect_merge_whitelist_committers_desc=Povolit pouze vyjmenovaným uživatelům nebo týmům slučovat pull requesty do této větve.
2383-
settings.protect_merge_whitelist_users=Povolení uživatelé pro slučování:
2384-
settings.protect_merge_whitelist_teams=Povolené týmy pro slučování:
23852373
settings.protect_check_status_contexts=Povolit kontrolu stavu
23862374
settings.protect_status_check_patterns=Vzorce kontroly stavu:
23872375
settings.protect_status_check_patterns_desc=Zadejte vzory pro určení, které kontroly stavu musí projít před sloučením větví do větve, která odpovídá tomuto pravidlu. Každý řádek určuje vzor. Vzory nemohou být prázdné.
@@ -2392,10 +2380,6 @@ settings.protect_invalid_status_check_pattern=Neplatný vzor kontroly stavu: „
23922380
settings.protect_no_valid_status_check_patterns=Žádné platné vzory kontroly stavu.
23932381
settings.protect_required_approvals=Požadovaná schválení:
23942382
settings.protect_required_approvals_desc=Umožnit sloučení pouze pull requestů s dostatečným pozitivním hodnocením.
2395-
settings.protect_approvals_whitelist_enabled=Omezit schválení na povolené uživatele nebo týmy
2396-
settings.protect_approvals_whitelist_enabled_desc=Do požadovaných schválení se započítají pouze posouzení od povolených uživatelů nebo týmů. Bez seznamu povolených se započítává schválení od kohokoli s právem zápisu.
2397-
settings.protect_approvals_whitelist_users=Povolení posuzovatelé:
2398-
settings.protect_approvals_whitelist_teams=Povolené týmy pro posuzování:
23992383
settings.dismiss_stale_approvals=Odmítnout nekvalitní schválení
24002384
settings.dismiss_stale_approvals_desc=Pokud budou do větve nahrány nové revize, které mění obsah tohoto pull requestu, všechna stará schválení budou zamítnuta.
24012385
settings.ignore_stale_approvals=Ignorovat zastaralá schválení

0 commit comments

Comments
 (0)