diff --git a/models/repo/git.go b/models/repo/git.go index 388bf86522..d39915e869 100644 --- a/models/repo/git.go +++ b/models/repo/git.go @@ -29,6 +29,15 @@ const ( MergeStyleRebaseUpdate MergeStyle = "rebase-update-only" ) +type UpdateStyle string + +const ( + // UpdateStyleMerge create merge commit to update + UpdateStyleMerge UpdateStyle = "merge" + // UpdateStyleRebase rebase to update + UpdateStyleRebase UpdateStyle = "rebase" +) + // UpdateDefaultBranch updates the default branch func UpdateDefaultBranch(ctx context.Context, repo *Repository) error { _, err := db.GetEngine(ctx).ID(repo.ID).Cols("default_branch").Update(repo) diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go index ed553844fc..5b4066d994 100644 --- a/models/repo/repo_unit.go +++ b/models/repo/repo_unit.go @@ -159,6 +159,7 @@ type PullRequestsConfig struct { AllowRebaseUpdate bool DefaultDeleteBranchAfterMerge bool DefaultMergeStyle MergeStyle + DefaultUpdateStyle UpdateStyle DefaultAllowMaintainerEdit bool } @@ -197,6 +198,25 @@ func (cfg *PullRequestsConfig) GetDefaultMergeStyle() MergeStyle { return MergeStyleMerge } +// IsUpdateStyleAllowed returns if update style is allowed +func (cfg *PullRequestsConfig) IsUpdateStyleAllowed(updateStyle UpdateStyle) bool { + return updateStyle == UpdateStyleMerge || + updateStyle == UpdateStyleRebase && cfg.AllowRebaseUpdate +} + +// GetDefaultUpdateStyle returns the default update style for this pull request +func (cfg *PullRequestsConfig) GetDefaultUpdateStyle() UpdateStyle { + if len(cfg.DefaultUpdateStyle) != 0 { + return cfg.DefaultUpdateStyle + } + + if setting.Repository.PullRequest.DefaultUpdateStyle != "" { + return UpdateStyle(setting.Repository.PullRequest.DefaultUpdateStyle) + } + + return UpdateStyleMerge +} + type ActionsConfig struct { DisabledWorkflows []string } diff --git a/models/repo/repo_unit_test.go b/models/repo/repo_unit_test.go index deee1a7472..129d913cfb 100644 --- a/models/repo/repo_unit_test.go +++ b/models/repo/repo_unit_test.go @@ -7,6 +7,8 @@ import ( "testing" "code.gitea.io/gitea/models/perm" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "github.com/stretchr/testify/assert" ) @@ -37,3 +39,50 @@ func TestRepoUnitAccessMode(t *testing.T) { assert.Equal(t, perm.AccessModeWrite, UnitAccessModeWrite.ToAccessMode(perm.AccessModeAdmin)) assert.Equal(t, perm.AccessModeRead, UnitAccessModeUnset.ToAccessMode(perm.AccessModeRead)) } + +func TestRepoPRIsUpdateStyleAllowed(t *testing.T) { + var cfg PullRequestsConfig + cfg = PullRequestsConfig{ + AllowRebaseUpdate: true, + } + assert.True(t, cfg.IsUpdateStyleAllowed(UpdateStyleMerge)) + assert.True(t, cfg.IsUpdateStyleAllowed(UpdateStyleRebase)) + + cfg = PullRequestsConfig{ + AllowRebaseUpdate: false, + } + assert.True(t, cfg.IsUpdateStyleAllowed(UpdateStyleMerge)) + assert.False(t, cfg.IsUpdateStyleAllowed(UpdateStyleRebase)) +} + +func TestRepoPRGetDefaultUpdateStyle(t *testing.T) { + defer test.MockVariableValue(&setting.Repository.PullRequest.DefaultUpdateStyle, "merge")() + + var cfg PullRequestsConfig + cfg = PullRequestsConfig{ + DefaultUpdateStyle: "", + } + assert.Equal(t, UpdateStyleMerge, cfg.GetDefaultUpdateStyle()) + cfg = PullRequestsConfig{ + DefaultUpdateStyle: "rebase", + } + assert.Equal(t, UpdateStyleRebase, cfg.GetDefaultUpdateStyle()) + cfg = PullRequestsConfig{ + DefaultUpdateStyle: "merge", + } + assert.Equal(t, UpdateStyleMerge, cfg.GetDefaultUpdateStyle()) + + setting.Repository.PullRequest.DefaultUpdateStyle = "rebase" + cfg = PullRequestsConfig{ + DefaultUpdateStyle: "", + } + assert.Equal(t, UpdateStyleRebase, cfg.GetDefaultUpdateStyle()) + cfg = PullRequestsConfig{ + DefaultUpdateStyle: "rebase", + } + assert.Equal(t, UpdateStyleRebase, cfg.GetDefaultUpdateStyle()) + cfg = PullRequestsConfig{ + DefaultUpdateStyle: "merge", + } + assert.Equal(t, UpdateStyleMerge, cfg.GetDefaultUpdateStyle()) +} diff --git a/modules/repository/create.go b/modules/repository/create.go index ca2150b972..32c6235544 100644 --- a/modules/repository/create.go +++ b/modules/repository/create.go @@ -89,8 +89,9 @@ func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, re Type: tp, Config: &repo_model.PullRequestsConfig{ AllowMerge: true, AllowRebase: true, AllowRebaseMerge: true, AllowSquash: true, AllowFastForwardOnly: true, - DefaultMergeStyle: repo_model.MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle), - AllowRebaseUpdate: true, + DefaultMergeStyle: repo_model.MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle), + DefaultUpdateStyle: repo_model.UpdateStyle(setting.Repository.PullRequest.DefaultUpdateStyle), + AllowRebaseUpdate: true, }, }) } else { diff --git a/modules/setting/repository.go b/modules/setting/repository.go index 6086dd1d57..d13f25f554 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -87,6 +87,7 @@ var ( DefaultMergeMessageAllAuthors bool DefaultMergeMessageMaxApprovers int DefaultMergeMessageOfficialApproversOnly bool + DefaultUpdateStyle string PopulateSquashCommentWithCommitMessages bool AddCoCommitterTrailers bool TestConflictingPatchesWithGitApply bool @@ -216,6 +217,7 @@ var ( DefaultMergeMessageAllAuthors bool DefaultMergeMessageMaxApprovers int DefaultMergeMessageOfficialApproversOnly bool + DefaultUpdateStyle string PopulateSquashCommentWithCommitMessages bool AddCoCommitterTrailers bool TestConflictingPatchesWithGitApply bool @@ -232,6 +234,7 @@ var ( DefaultMergeMessageAllAuthors: false, DefaultMergeMessageMaxApprovers: 10, DefaultMergeMessageOfficialApproversOnly: true, + DefaultUpdateStyle: "merge", PopulateSquashCommentWithCommitMessages: false, AddCoCommitterTrailers: true, RetargetChildrenOnMerge: true, diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 36190fe36b..b5f54a2a7a 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -105,6 +105,7 @@ type Repository struct { DefaultDeleteBranchAfterMerge bool `json:"default_delete_branch_after_merge"` DefaultMergeStyle string `json:"default_merge_style"` DefaultAllowMaintainerEdit bool `json:"default_allow_maintainer_edit"` + DefaultUpdateStyle string `json:"default_update_style"` AvatarURL string `json:"avatar_url"` Internal bool `json:"internal"` MirrorInterval string `json:"mirror_interval"` @@ -225,6 +226,8 @@ type EditRepoOption struct { DefaultDeleteBranchAfterMerge *bool `json:"default_delete_branch_after_merge,omitempty"` // set to a merge style to be used by this repository: "merge", "rebase", "rebase-merge", "squash", or "fast-forward-only". DefaultMergeStyle *string `json:"default_merge_style,omitempty"` + // set to a update style to be used by this repository: "rebase" or "merge" + DefaultUpdateStyle *string `json:"default_update_style,omitempty"` // set to `true` to allow edits from maintainers by default DefaultAllowMaintainerEdit *bool `json:"default_allow_maintainer_edit,omitempty"` // set to `true` to archive this repository. diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 6e1524f583..3b413b8f92 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2246,6 +2246,7 @@ settings.pulls_desc = Enable repository pull requests settings.pulls.ignore_whitespace = Ignore whitespace for conflicts settings.pulls.enable_autodetect_manual_merge = Enable autodetect manual merge (Note: In some special cases, misjudgments can occur) settings.pulls.allow_rebase_update = Enable updating pull request branch by rebase +settings.default_update_style_desc=Default update style used for updating pull requests that are behind the base branch. settings.pulls.default_delete_branch_after_merge = Delete pull request branch after merge by default settings.pulls.default_allow_edits_from_maintainers = Allow edits from maintainers by default settings.releases_desc = Enable repository releases diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 93d40d2dbf..04c6fde453 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -937,6 +937,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { AllowRebaseUpdate: true, DefaultDeleteBranchAfterMerge: false, DefaultMergeStyle: repo_model.MergeStyleMerge, + DefaultUpdateStyle: repo_model.UpdateStyleMerge, DefaultAllowMaintainerEdit: false, } } else { @@ -976,6 +977,9 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { if opts.DefaultMergeStyle != nil { config.DefaultMergeStyle = repo_model.MergeStyle(*opts.DefaultMergeStyle) } + if opts.DefaultUpdateStyle != nil { + config.DefaultUpdateStyle = repo_model.UpdateStyle(*opts.DefaultUpdateStyle) + } if opts.DefaultAllowMaintainerEdit != nil { config.DefaultAllowMaintainerEdit = *opts.DefaultAllowMaintainerEdit } diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 78fb5e6c01..c154a9b665 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1918,6 +1918,21 @@ func ViewIssue(ctx *context.Context) { ctx.Data["MergeStyle"] = mergeStyle + var updateStyle repo_model.UpdateStyle + // Check correct values and select default + if ms, ok := ctx.Data["UpdateStyle"].(repo_model.UpdateStyle); !ok || + !prConfig.IsUpdateStyleAllowed(ms) { + defaultUpdateStyle := prConfig.GetDefaultUpdateStyle() + if prConfig.IsUpdateStyleAllowed(defaultUpdateStyle) && !ok { + updateStyle = defaultUpdateStyle + } else if prConfig.AllowMerge { + updateStyle = repo_model.UpdateStyleMerge + } else if prConfig.AllowRebase { + updateStyle = repo_model.UpdateStyleRebase + } + } + ctx.Data["UpdateStyle"] = updateStyle + defaultMergeMessage, defaultMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, mergeStyle) if err != nil { ctx.ServerError("GetDefaultMergeMessage", err) diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index ce506eafb1..2c6ca77a6a 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -262,6 +262,7 @@ func UnitsPost(ctx *context.Context) { AllowRebaseUpdate: form.PullsAllowRebaseUpdate, DefaultDeleteBranchAfterMerge: form.DefaultDeleteBranchAfterMerge, DefaultMergeStyle: repo_model.MergeStyle(form.PullsDefaultMergeStyle), + DefaultUpdateStyle: repo_model.UpdateStyle(form.PullsDefaultUpdateStyle), DefaultAllowMaintainerEdit: form.DefaultAllowMaintainerEdit, }, }) diff --git a/services/convert/repository.go b/services/convert/repository.go index 2fb6f6d7c0..e4b2c7b8bc 100644 --- a/services/convert/repository.go +++ b/services/convert/repository.go @@ -101,6 +101,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR allowRebaseUpdate := false defaultDeleteBranchAfterMerge := false defaultMergeStyle := repo_model.MergeStyleMerge + defaultUpdateStyle := repo_model.UpdateStyleMerge defaultAllowMaintainerEdit := false if unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests); err == nil { config := unit.PullRequestsConfig() @@ -114,6 +115,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR allowRebaseUpdate = config.AllowRebaseUpdate defaultDeleteBranchAfterMerge = config.DefaultDeleteBranchAfterMerge defaultMergeStyle = config.GetDefaultMergeStyle() + defaultUpdateStyle = config.GetDefaultUpdateStyle() defaultAllowMaintainerEdit = config.DefaultAllowMaintainerEdit } hasProjects := false @@ -231,6 +233,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR AllowRebaseUpdate: allowRebaseUpdate, DefaultDeleteBranchAfterMerge: defaultDeleteBranchAfterMerge, DefaultMergeStyle: string(defaultMergeStyle), + DefaultUpdateStyle: string(defaultUpdateStyle), DefaultAllowMaintainerEdit: defaultAllowMaintainerEdit, AvatarURL: repo.AvatarLink(ctx), Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate, diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index f6e184fcb6..1ce9b298ad 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -189,6 +189,7 @@ type RepoUnitSettingForm struct { PullsAllowFastForwardOnly bool PullsAllowManualMerge bool PullsDefaultMergeStyle string + PullsDefaultUpdateStyle string EnableAutodetectManualMerge bool PullsAllowRebaseUpdate bool DefaultDeleteBranchAfterMerge bool diff --git a/templates/repo/issue/view_content/update_branch_by_merge.tmpl b/templates/repo/issue/view_content/update_branch_by_merge.tmpl index adce052dee..9fbc8b018b 100644 --- a/templates/repo/issue/view_content/update_branch_by_merge.tmpl +++ b/templates/repo/issue/view_content/update_branch_by_merge.tmpl @@ -9,23 +9,31 @@ {{if and $.UpdateAllowed $.UpdateByRebaseAllowed}}
-
{{end}} {{if and $.UpdateAllowed (not $.UpdateByRebaseAllowed)}} -
+ {{$.CsrfTokenHtml}}