mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-26 05:33:52 +03:00
feat: allow changing default branch update style
This commit allows chaning default branch update style through global and repository settings. The setting affects "Update branch" button in PR view (button shows when some commits are ahead of master branch). When default update style is set to "rebase", dropdown button updates branch by rebase by default. When update style is set to other value, dropdown button updates branch by merge. Any of these actions may be selected using dropdown in any case. Signed-off-by: George Bartolomey <george@bh4.ru>
This commit is contained in:
parent
0bebecc968
commit
13ca6c14f1
16 changed files with 257 additions and 7 deletions
|
@ -29,6 +29,15 @@ const (
|
||||||
MergeStyleRebaseUpdate MergeStyle = "rebase-update-only"
|
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
|
// UpdateDefaultBranch updates the default branch
|
||||||
func UpdateDefaultBranch(ctx context.Context, repo *Repository) error {
|
func UpdateDefaultBranch(ctx context.Context, repo *Repository) error {
|
||||||
_, err := db.GetEngine(ctx).ID(repo.ID).Cols("default_branch").Update(repo)
|
_, err := db.GetEngine(ctx).ID(repo.ID).Cols("default_branch").Update(repo)
|
||||||
|
|
|
@ -159,6 +159,7 @@ type PullRequestsConfig struct {
|
||||||
AllowRebaseUpdate bool
|
AllowRebaseUpdate bool
|
||||||
DefaultDeleteBranchAfterMerge bool
|
DefaultDeleteBranchAfterMerge bool
|
||||||
DefaultMergeStyle MergeStyle
|
DefaultMergeStyle MergeStyle
|
||||||
|
DefaultUpdateStyle UpdateStyle
|
||||||
DefaultAllowMaintainerEdit bool
|
DefaultAllowMaintainerEdit bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +198,25 @@ func (cfg *PullRequestsConfig) GetDefaultMergeStyle() MergeStyle {
|
||||||
return MergeStyleMerge
|
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 {
|
type ActionsConfig struct {
|
||||||
DisabledWorkflows []string
|
DisabledWorkflows []string
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"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.AccessModeWrite, UnitAccessModeWrite.ToAccessMode(perm.AccessModeAdmin))
|
||||||
assert.Equal(t, perm.AccessModeRead, UnitAccessModeUnset.ToAccessMode(perm.AccessModeRead))
|
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())
|
||||||
|
}
|
||||||
|
|
|
@ -90,6 +90,7 @@ func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, re
|
||||||
Config: &repo_model.PullRequestsConfig{
|
Config: &repo_model.PullRequestsConfig{
|
||||||
AllowMerge: true, AllowRebase: true, AllowRebaseMerge: true, AllowSquash: true, AllowFastForwardOnly: true,
|
AllowMerge: true, AllowRebase: true, AllowRebaseMerge: true, AllowSquash: true, AllowFastForwardOnly: true,
|
||||||
DefaultMergeStyle: repo_model.MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle),
|
DefaultMergeStyle: repo_model.MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle),
|
||||||
|
DefaultUpdateStyle: repo_model.UpdateStyle(setting.Repository.PullRequest.DefaultUpdateStyle),
|
||||||
AllowRebaseUpdate: true,
|
AllowRebaseUpdate: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -87,6 +87,7 @@ var (
|
||||||
DefaultMergeMessageAllAuthors bool
|
DefaultMergeMessageAllAuthors bool
|
||||||
DefaultMergeMessageMaxApprovers int
|
DefaultMergeMessageMaxApprovers int
|
||||||
DefaultMergeMessageOfficialApproversOnly bool
|
DefaultMergeMessageOfficialApproversOnly bool
|
||||||
|
DefaultUpdateStyle string
|
||||||
PopulateSquashCommentWithCommitMessages bool
|
PopulateSquashCommentWithCommitMessages bool
|
||||||
AddCoCommitterTrailers bool
|
AddCoCommitterTrailers bool
|
||||||
TestConflictingPatchesWithGitApply bool
|
TestConflictingPatchesWithGitApply bool
|
||||||
|
@ -216,6 +217,7 @@ var (
|
||||||
DefaultMergeMessageAllAuthors bool
|
DefaultMergeMessageAllAuthors bool
|
||||||
DefaultMergeMessageMaxApprovers int
|
DefaultMergeMessageMaxApprovers int
|
||||||
DefaultMergeMessageOfficialApproversOnly bool
|
DefaultMergeMessageOfficialApproversOnly bool
|
||||||
|
DefaultUpdateStyle string
|
||||||
PopulateSquashCommentWithCommitMessages bool
|
PopulateSquashCommentWithCommitMessages bool
|
||||||
AddCoCommitterTrailers bool
|
AddCoCommitterTrailers bool
|
||||||
TestConflictingPatchesWithGitApply bool
|
TestConflictingPatchesWithGitApply bool
|
||||||
|
@ -232,6 +234,7 @@ var (
|
||||||
DefaultMergeMessageAllAuthors: false,
|
DefaultMergeMessageAllAuthors: false,
|
||||||
DefaultMergeMessageMaxApprovers: 10,
|
DefaultMergeMessageMaxApprovers: 10,
|
||||||
DefaultMergeMessageOfficialApproversOnly: true,
|
DefaultMergeMessageOfficialApproversOnly: true,
|
||||||
|
DefaultUpdateStyle: "merge",
|
||||||
PopulateSquashCommentWithCommitMessages: false,
|
PopulateSquashCommentWithCommitMessages: false,
|
||||||
AddCoCommitterTrailers: true,
|
AddCoCommitterTrailers: true,
|
||||||
RetargetChildrenOnMerge: true,
|
RetargetChildrenOnMerge: true,
|
||||||
|
|
|
@ -105,6 +105,7 @@ type Repository struct {
|
||||||
DefaultDeleteBranchAfterMerge bool `json:"default_delete_branch_after_merge"`
|
DefaultDeleteBranchAfterMerge bool `json:"default_delete_branch_after_merge"`
|
||||||
DefaultMergeStyle string `json:"default_merge_style"`
|
DefaultMergeStyle string `json:"default_merge_style"`
|
||||||
DefaultAllowMaintainerEdit bool `json:"default_allow_maintainer_edit"`
|
DefaultAllowMaintainerEdit bool `json:"default_allow_maintainer_edit"`
|
||||||
|
DefaultUpdateStyle string `json:"default_update_style"`
|
||||||
AvatarURL string `json:"avatar_url"`
|
AvatarURL string `json:"avatar_url"`
|
||||||
Internal bool `json:"internal"`
|
Internal bool `json:"internal"`
|
||||||
MirrorInterval string `json:"mirror_interval"`
|
MirrorInterval string `json:"mirror_interval"`
|
||||||
|
@ -225,6 +226,8 @@ type EditRepoOption struct {
|
||||||
DefaultDeleteBranchAfterMerge *bool `json:"default_delete_branch_after_merge,omitempty"`
|
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".
|
// 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"`
|
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
|
// set to `true` to allow edits from maintainers by default
|
||||||
DefaultAllowMaintainerEdit *bool `json:"default_allow_maintainer_edit,omitempty"`
|
DefaultAllowMaintainerEdit *bool `json:"default_allow_maintainer_edit,omitempty"`
|
||||||
// set to `true` to archive this repository.
|
// set to `true` to archive this repository.
|
||||||
|
|
|
@ -2246,6 +2246,7 @@ settings.pulls_desc = Enable repository pull requests
|
||||||
settings.pulls.ignore_whitespace = Ignore whitespace for conflicts
|
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.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.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_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.pulls.default_allow_edits_from_maintainers = Allow edits from maintainers by default
|
||||||
settings.releases_desc = Enable repository releases
|
settings.releases_desc = Enable repository releases
|
||||||
|
|
|
@ -937,6 +937,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||||
AllowRebaseUpdate: true,
|
AllowRebaseUpdate: true,
|
||||||
DefaultDeleteBranchAfterMerge: false,
|
DefaultDeleteBranchAfterMerge: false,
|
||||||
DefaultMergeStyle: repo_model.MergeStyleMerge,
|
DefaultMergeStyle: repo_model.MergeStyleMerge,
|
||||||
|
DefaultUpdateStyle: repo_model.UpdateStyleMerge,
|
||||||
DefaultAllowMaintainerEdit: false,
|
DefaultAllowMaintainerEdit: false,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -976,6 +977,9 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||||
if opts.DefaultMergeStyle != nil {
|
if opts.DefaultMergeStyle != nil {
|
||||||
config.DefaultMergeStyle = repo_model.MergeStyle(*opts.DefaultMergeStyle)
|
config.DefaultMergeStyle = repo_model.MergeStyle(*opts.DefaultMergeStyle)
|
||||||
}
|
}
|
||||||
|
if opts.DefaultUpdateStyle != nil {
|
||||||
|
config.DefaultUpdateStyle = repo_model.UpdateStyle(*opts.DefaultUpdateStyle)
|
||||||
|
}
|
||||||
if opts.DefaultAllowMaintainerEdit != nil {
|
if opts.DefaultAllowMaintainerEdit != nil {
|
||||||
config.DefaultAllowMaintainerEdit = *opts.DefaultAllowMaintainerEdit
|
config.DefaultAllowMaintainerEdit = *opts.DefaultAllowMaintainerEdit
|
||||||
}
|
}
|
||||||
|
|
|
@ -1918,6 +1918,21 @@ func ViewIssue(ctx *context.Context) {
|
||||||
|
|
||||||
ctx.Data["MergeStyle"] = mergeStyle
|
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)
|
defaultMergeMessage, defaultMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, mergeStyle)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetDefaultMergeMessage", err)
|
ctx.ServerError("GetDefaultMergeMessage", err)
|
||||||
|
|
|
@ -262,6 +262,7 @@ func UnitsPost(ctx *context.Context) {
|
||||||
AllowRebaseUpdate: form.PullsAllowRebaseUpdate,
|
AllowRebaseUpdate: form.PullsAllowRebaseUpdate,
|
||||||
DefaultDeleteBranchAfterMerge: form.DefaultDeleteBranchAfterMerge,
|
DefaultDeleteBranchAfterMerge: form.DefaultDeleteBranchAfterMerge,
|
||||||
DefaultMergeStyle: repo_model.MergeStyle(form.PullsDefaultMergeStyle),
|
DefaultMergeStyle: repo_model.MergeStyle(form.PullsDefaultMergeStyle),
|
||||||
|
DefaultUpdateStyle: repo_model.UpdateStyle(form.PullsDefaultUpdateStyle),
|
||||||
DefaultAllowMaintainerEdit: form.DefaultAllowMaintainerEdit,
|
DefaultAllowMaintainerEdit: form.DefaultAllowMaintainerEdit,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -101,6 +101,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
|
||||||
allowRebaseUpdate := false
|
allowRebaseUpdate := false
|
||||||
defaultDeleteBranchAfterMerge := false
|
defaultDeleteBranchAfterMerge := false
|
||||||
defaultMergeStyle := repo_model.MergeStyleMerge
|
defaultMergeStyle := repo_model.MergeStyleMerge
|
||||||
|
defaultUpdateStyle := repo_model.UpdateStyleMerge
|
||||||
defaultAllowMaintainerEdit := false
|
defaultAllowMaintainerEdit := false
|
||||||
if unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests); err == nil {
|
if unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests); err == nil {
|
||||||
config := unit.PullRequestsConfig()
|
config := unit.PullRequestsConfig()
|
||||||
|
@ -114,6 +115,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
|
||||||
allowRebaseUpdate = config.AllowRebaseUpdate
|
allowRebaseUpdate = config.AllowRebaseUpdate
|
||||||
defaultDeleteBranchAfterMerge = config.DefaultDeleteBranchAfterMerge
|
defaultDeleteBranchAfterMerge = config.DefaultDeleteBranchAfterMerge
|
||||||
defaultMergeStyle = config.GetDefaultMergeStyle()
|
defaultMergeStyle = config.GetDefaultMergeStyle()
|
||||||
|
defaultUpdateStyle = config.GetDefaultUpdateStyle()
|
||||||
defaultAllowMaintainerEdit = config.DefaultAllowMaintainerEdit
|
defaultAllowMaintainerEdit = config.DefaultAllowMaintainerEdit
|
||||||
}
|
}
|
||||||
hasProjects := false
|
hasProjects := false
|
||||||
|
@ -231,6 +233,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
|
||||||
AllowRebaseUpdate: allowRebaseUpdate,
|
AllowRebaseUpdate: allowRebaseUpdate,
|
||||||
DefaultDeleteBranchAfterMerge: defaultDeleteBranchAfterMerge,
|
DefaultDeleteBranchAfterMerge: defaultDeleteBranchAfterMerge,
|
||||||
DefaultMergeStyle: string(defaultMergeStyle),
|
DefaultMergeStyle: string(defaultMergeStyle),
|
||||||
|
DefaultUpdateStyle: string(defaultUpdateStyle),
|
||||||
DefaultAllowMaintainerEdit: defaultAllowMaintainerEdit,
|
DefaultAllowMaintainerEdit: defaultAllowMaintainerEdit,
|
||||||
AvatarURL: repo.AvatarLink(ctx),
|
AvatarURL: repo.AvatarLink(ctx),
|
||||||
Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
|
Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
|
||||||
|
|
|
@ -189,6 +189,7 @@ type RepoUnitSettingForm struct {
|
||||||
PullsAllowFastForwardOnly bool
|
PullsAllowFastForwardOnly bool
|
||||||
PullsAllowManualMerge bool
|
PullsAllowManualMerge bool
|
||||||
PullsDefaultMergeStyle string
|
PullsDefaultMergeStyle string
|
||||||
|
PullsDefaultUpdateStyle string
|
||||||
EnableAutodetectManualMerge bool
|
EnableAutodetectManualMerge bool
|
||||||
PullsAllowRebaseUpdate bool
|
PullsAllowRebaseUpdate bool
|
||||||
DefaultDeleteBranchAfterMerge bool
|
DefaultDeleteBranchAfterMerge bool
|
||||||
|
|
|
@ -9,23 +9,31 @@
|
||||||
{{if and $.UpdateAllowed $.UpdateByRebaseAllowed}}
|
{{if and $.UpdateAllowed $.UpdateByRebaseAllowed}}
|
||||||
<div class="tw-inline-block">
|
<div class="tw-inline-block">
|
||||||
<div class="ui buttons update-button">
|
<div class="ui buttons update-button">
|
||||||
<button class="ui button" data-do="{{$.Link}}/update" data-redirect="{{$.Link}}">
|
<button class="ui button" data-do="{{$.Link}}/update?style={{$.UpdateStyle}}" data-redirect="{{$.Link}}">
|
||||||
<span class="button-text">
|
<span class="button-text">
|
||||||
|
{{if eq $.UpdateStyle "rebase"}}
|
||||||
|
{{ctx.Locale.Tr "repo.pulls.update_branch_rebase"}}
|
||||||
|
{{else}}
|
||||||
{{ctx.Locale.Tr "repo.pulls.update_branch"}}
|
{{ctx.Locale.Tr "repo.pulls.update_branch"}}
|
||||||
|
{{end}}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="ui dropdown icon button">
|
<div class="ui dropdown icon button">
|
||||||
{{svg "octicon-triangle-down"}}
|
{{svg "octicon-triangle-down"}}
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<a class="item active selected" data-do="{{$.Link}}/update">{{ctx.Locale.Tr "repo.pulls.update_branch"}}</a>
|
<a class="item {{if ne $.UpdateStyle "rebase"}}active selected{{end}}" data-do="{{$.Link}}/update?style=merge">
|
||||||
<a class="item" data-do="{{$.Link}}/update?style=rebase">{{ctx.Locale.Tr "repo.pulls.update_branch_rebase"}}</a>
|
{{ctx.Locale.Tr "repo.pulls.update_branch"}}
|
||||||
|
</a>
|
||||||
|
<a class="item {{if eq $.UpdateStyle "rebase"}}active selected{{end}}" data-do="{{$.Link}}/update?style=rebase">
|
||||||
|
{{ctx.Locale.Tr "repo.pulls.update_branch_rebase"}}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if and $.UpdateAllowed (not $.UpdateByRebaseAllowed)}}
|
{{if and $.UpdateAllowed (not $.UpdateByRebaseAllowed)}}
|
||||||
<form action="{{$.Link}}/update" method="post" class="ui update-branch-form">
|
<form action="{{$.Link}}/update?style=merge" method="post" class="ui update-branch-form">
|
||||||
{{$.CsrfTokenHtml}}
|
{{$.CsrfTokenHtml}}
|
||||||
<button class="ui compact button">
|
<button class="ui compact button">
|
||||||
<span class="ui text">{{ctx.Locale.Tr "repo.pulls.update_branch"}}</span>
|
<span class="ui text">{{ctx.Locale.Tr "repo.pulls.update_branch"}}</span>
|
||||||
|
|
|
@ -105,6 +105,29 @@
|
||||||
<label>{{ctx.Locale.Tr "repo.settings.pulls.allow_rebase_update"}}</label>
|
<label>{{ctx.Locale.Tr "repo.settings.pulls.allow_rebase_update"}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<p>
|
||||||
|
{{ctx.Locale.Tr "repo.settings.default_update_style_desc"}}
|
||||||
|
</p>
|
||||||
|
<div class="ui dropdown selection">
|
||||||
|
<select name="pulls_default_update_style">
|
||||||
|
<option value="merge" {{if or (not $pullRequestEnabled) (eq $prUnit.PullRequestsConfig.DefaultUpdateStyle "merge")}}selected{{end}}>{{ctx.Locale.Tr "repo.pulls.update_branch"}}</option>
|
||||||
|
<option value="rebase" {{if or (not $pullRequestEnabled) (eq $prUnit.PullRequestsConfig.DefaultUpdateStyle "rebase")}}selected{{end}}>{{ctx.Locale.Tr "repo.pulls.update_branch_rebase"}}</option>
|
||||||
|
</select>{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
|
<div class="default text">
|
||||||
|
{{if (eq $prUnit.PullRequestsConfig.DefaultUpdateStyle "merge")}}
|
||||||
|
{{ctx.Locale.Tr "repo.pulls.update_branch"}}
|
||||||
|
{{end}}
|
||||||
|
{{if (eq $prUnit.PullRequestsConfig.DefaultUpdateStyle "rebase")}}
|
||||||
|
{{ctx.Locale.Tr "repo.pulls.update_branch_rebase"}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<div class="menu">
|
||||||
|
<div class="item" data-value="merge">{{ctx.Locale.Tr "repo.pulls.update_branch"}}</div>
|
||||||
|
<div class="item" data-value="rebase">{{ctx.Locale.Tr "repo.pulls.update_branch_rebase"}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input name="default_delete_branch_after_merge" type="checkbox" {{if or (not $pullRequestEnabled) ($prUnit.PullRequestsConfig.DefaultDeleteBranchAfterMerge)}}checked{{end}}>
|
<input name="default_delete_branch_after_merge" type="checkbox" {{if or (not $pullRequestEnabled) ($prUnit.PullRequestsConfig.DefaultDeleteBranchAfterMerge)}}checked{{end}}>
|
||||||
|
|
9
templates/swagger/v1_json.tmpl
generated
9
templates/swagger/v1_json.tmpl
generated
|
@ -23321,6 +23321,11 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "DefaultMergeStyle"
|
"x-go-name": "DefaultMergeStyle"
|
||||||
},
|
},
|
||||||
|
"default_update_style": {
|
||||||
|
"description": "set to a update style to be used by this repository: \"rebase\" or \"merge\"",
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "DefaultUpdateStyle"
|
||||||
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"description": "a short description of the repository.",
|
"description": "a short description of the repository.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -26605,6 +26610,10 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "DefaultMergeStyle"
|
"x-go-name": "DefaultMergeStyle"
|
||||||
},
|
},
|
||||||
|
"default_update_style": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "DefaultUpdateStyle"
|
||||||
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "Description"
|
"x-go-name": "Description"
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -16,6 +17,9 @@ import (
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
pull_service "code.gitea.io/gitea/services/pull"
|
pull_service "code.gitea.io/gitea/services/pull"
|
||||||
repo_service "code.gitea.io/gitea/services/repository"
|
repo_service "code.gitea.io/gitea/services/repository"
|
||||||
files_service "code.gitea.io/gitea/services/repository/files"
|
files_service "code.gitea.io/gitea/services/repository/files"
|
||||||
|
@ -83,6 +87,102 @@ func TestAPIPullUpdateByRebase(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAPIViewUpdateSettings(t *testing.T) {
|
||||||
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
// Create PR to test
|
||||||
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
org26 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 26})
|
||||||
|
pr := createOutdatedPR(t, user, org26)
|
||||||
|
|
||||||
|
// Test GetDiverging
|
||||||
|
diffCount, err := pull_service.GetDiverging(git.DefaultContext, pr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, diffCount.Behind)
|
||||||
|
assert.EqualValues(t, 1, diffCount.Ahead)
|
||||||
|
require.NoError(t, pr.LoadBaseRepo(db.DefaultContext))
|
||||||
|
require.NoError(t, pr.LoadIssue(db.DefaultContext))
|
||||||
|
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
|
||||||
|
|
||||||
|
defaultUpdateStyle := "rebase"
|
||||||
|
editOption := api.EditRepoOption{
|
||||||
|
DefaultUpdateStyle: &defaultUpdateStyle,
|
||||||
|
}
|
||||||
|
|
||||||
|
req := NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/%s/%s", pr.BaseRepo.OwnerName, pr.BaseRepo.Name), editOption).AddTokenAuth(token)
|
||||||
|
session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
assertViewPullUpdate(t, pr, session, "rebase", true)
|
||||||
|
|
||||||
|
defaultUpdateStyle = "merge"
|
||||||
|
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/%s/%s", pr.BaseRepo.OwnerName, pr.BaseRepo.Name), editOption).AddTokenAuth(token)
|
||||||
|
session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
assertViewPullUpdate(t, pr, session, "merge", true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestViewPullUpdateByMerge(t *testing.T) {
|
||||||
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
|
testViewPullUpdate(t, "merge")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestViewPullUpdateByRebase(t *testing.T) {
|
||||||
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
|
testViewPullUpdate(t, "rebase")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testViewPullUpdate(t *testing.T, updateStyle string) {
|
||||||
|
defer test.MockVariableValue(&setting.Repository.PullRequest.DefaultUpdateStyle, updateStyle)()
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
// Create PR to test
|
||||||
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
org26 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 26})
|
||||||
|
pr := createOutdatedPR(t, user, org26)
|
||||||
|
|
||||||
|
// Test GetDiverging
|
||||||
|
diffCount, err := pull_service.GetDiverging(git.DefaultContext, pr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, diffCount.Behind)
|
||||||
|
assert.EqualValues(t, 1, diffCount.Ahead)
|
||||||
|
require.NoError(t, pr.LoadBaseRepo(db.DefaultContext))
|
||||||
|
require.NoError(t, pr.LoadIssue(db.DefaultContext))
|
||||||
|
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
assertViewPullUpdate(t, pr, session, updateStyle, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertViewPullUpdate(t *testing.T, pr *issues_model.PullRequest, session *TestSession, expectedStyle string, dropdownExpected bool) {
|
||||||
|
req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/pulls/%d", pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Issue.Index))
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
|
// Verify that URL of the update button is shown correctly.
|
||||||
|
var mainExpectedURL string
|
||||||
|
mergeExpectedURL := fmt.Sprintf("/%s/%s/pulls/%d/update?style=merge", pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Issue.Index)
|
||||||
|
rebaseExpectedURL := fmt.Sprintf("/%s/%s/pulls/%d/update?style=rebase", pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Issue.Index)
|
||||||
|
if expectedStyle == "rebase" {
|
||||||
|
mainExpectedURL = rebaseExpectedURL
|
||||||
|
if dropdownExpected {
|
||||||
|
htmlDoc.AssertElement(t, fmt.Sprintf(".update-button .dropdown .menu .item[data-do=\"%s\"]:not(.active.selected)", mergeExpectedURL), true)
|
||||||
|
htmlDoc.AssertElement(t, fmt.Sprintf(".update-button .dropdown .menu .active.selected.item[data-do=\"%s\"]", rebaseExpectedURL), true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mainExpectedURL = mergeExpectedURL
|
||||||
|
if dropdownExpected {
|
||||||
|
htmlDoc.AssertElement(t, fmt.Sprintf(".update-button .dropdown .menu .active.selected.item[data-do=\"%s\"]", mergeExpectedURL), true)
|
||||||
|
htmlDoc.AssertElement(t, fmt.Sprintf(".update-button .dropdown .menu .item[data-do=\"%s\"]:not(.active.selected)", rebaseExpectedURL), true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dropdownExpected {
|
||||||
|
htmlDoc.AssertElement(t, fmt.Sprintf(".update-button .button[data-do=\"%s\"]", mainExpectedURL), true)
|
||||||
|
} else {
|
||||||
|
htmlDoc.AssertElement(t, fmt.Sprintf("form[action=\"%s\"]", mainExpectedURL), true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_model.PullRequest {
|
func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_model.PullRequest {
|
||||||
baseRepo, _, _ := tests.CreateDeclarativeRepo(t, actor, "repo-pr-update", nil, nil, nil)
|
baseRepo, _, _ := tests.CreateDeclarativeRepo(t, actor, "repo-pr-update", nil, nil, nil)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue