mirror of
https://github.com/go-gitea/gitea.git
synced 2026-02-09 02:09:25 +08:00
This adds a per-repository default PR base branch and wires it through PR entry points. It updates compare links and recently pushed branch prompts to respect the configured base branch, and prevents auto-merge cleanup from deleting the configured base branch on same-repo PRs. ## Behavior changes - New PR compare links on repo home/issue list and branch list honor the configured default PR base branch. - The "recently pushed new branches" prompt now compares against the configured base branch. - Auto-merge branch cleanup skips deleting the configured base branch (same-repo PRs only). --------- Signed-off-by: Louis <116039387+tototomate123@users.noreply.github.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
@@ -490,12 +490,25 @@ func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, o
|
|||||||
opts.CommitAfterUnix = time.Now().Add(-time.Hour * 2).Unix()
|
opts.CommitAfterUnix = time.Now().Add(-time.Hour * 2).Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
baseBranch, err := GetBranch(ctx, opts.BaseRepo.ID, opts.BaseRepo.DefaultBranch)
|
var ignoredCommitIDs []string
|
||||||
|
baseDefaultBranch, err := GetBranch(ctx, opts.BaseRepo.ID, opts.BaseRepo.DefaultBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
log.Warn("GetBranch:DefaultBranch: %v", err)
|
||||||
|
} else {
|
||||||
|
ignoredCommitIDs = append(ignoredCommitIDs, baseDefaultBranch.CommitID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// find all related branches, these branches may already created PRs, we will check later
|
baseDefaultTargetBranchName := opts.BaseRepo.MustGetUnit(ctx, unit.TypePullRequests).PullRequestsConfig().DefaultTargetBranch
|
||||||
|
if baseDefaultTargetBranchName != "" && baseDefaultTargetBranchName != opts.BaseRepo.DefaultBranch {
|
||||||
|
baseDefaultTargetBranch, err := GetBranch(ctx, opts.BaseRepo.ID, baseDefaultTargetBranchName)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("GetBranch:DefaultTargetBranch: %v", err)
|
||||||
|
} else {
|
||||||
|
ignoredCommitIDs = append(ignoredCommitIDs, baseDefaultTargetBranch.CommitID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find all related branches, these branches may already have PRs, we will check later
|
||||||
var branches []*Branch
|
var branches []*Branch
|
||||||
if err := db.GetEngine(ctx).
|
if err := db.GetEngine(ctx).
|
||||||
Where(builder.And(
|
Where(builder.And(
|
||||||
@@ -506,7 +519,7 @@ func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, o
|
|||||||
builder.Gte{"commit_time": opts.CommitAfterUnix},
|
builder.Gte{"commit_time": opts.CommitAfterUnix},
|
||||||
builder.In("repo_id", repoIDs),
|
builder.In("repo_id", repoIDs),
|
||||||
// newly created branch have no changes, so skip them
|
// newly created branch have no changes, so skip them
|
||||||
builder.Neq{"commit_id": baseBranch.CommitID},
|
builder.NotIn("commit_id", ignoredCommitIDs),
|
||||||
)).
|
)).
|
||||||
OrderBy(db.SearchOrderByRecentUpdated.String()).
|
OrderBy(db.SearchOrderByRecentUpdated.String()).
|
||||||
Find(&branches); err != nil {
|
Find(&branches); err != nil {
|
||||||
@@ -514,10 +527,8 @@ func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, o
|
|||||||
}
|
}
|
||||||
|
|
||||||
newBranches := make([]*RecentlyPushedNewBranch, 0, len(branches))
|
newBranches := make([]*RecentlyPushedNewBranch, 0, len(branches))
|
||||||
if opts.MaxCount == 0 {
|
opts.MaxCount = util.IfZero(opts.MaxCount, 2) // by default, we display 2 recently pushed new branch
|
||||||
// by default we display 2 recently pushed new branch
|
baseTargetBranchName := opts.BaseRepo.GetPullRequestTargetBranch(ctx)
|
||||||
opts.MaxCount = 2
|
|
||||||
}
|
|
||||||
for _, branch := range branches {
|
for _, branch := range branches {
|
||||||
// whether the branch is protected
|
// whether the branch is protected
|
||||||
protected, err := IsBranchProtected(ctx, branch.RepoID, branch.Name)
|
protected, err := IsBranchProtected(ctx, branch.RepoID, branch.Name)
|
||||||
@@ -555,7 +566,7 @@ func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, o
|
|||||||
BranchDisplayName: branchDisplayName,
|
BranchDisplayName: branchDisplayName,
|
||||||
BranchName: branch.Name,
|
BranchName: branch.Name,
|
||||||
BranchLink: fmt.Sprintf("%s/src/branch/%s", branch.Repo.Link(), util.PathEscapeSegments(branch.Name)),
|
BranchLink: fmt.Sprintf("%s/src/branch/%s", branch.Repo.Link(), util.PathEscapeSegments(branch.Name)),
|
||||||
BranchCompareURL: branch.Repo.ComposeBranchCompareURL(opts.BaseRepo, branch.Name),
|
BranchCompareURL: branch.Repo.ComposeBranchCompareURL(opts.BaseRepo, baseTargetBranchName, branch.Name),
|
||||||
CommitTime: branch.CommitTime,
|
CommitTime: branch.CommitTime,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
16
models/repo/pull_request_default.go
Normal file
16
models/repo/pull_request_default.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/unit"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (repo *Repository) GetPullRequestTargetBranch(ctx context.Context) string {
|
||||||
|
unitPRConfig := repo.MustGetUnit(ctx, unit.TypePullRequests).PullRequestsConfig()
|
||||||
|
return util.IfZero(unitPRConfig.DefaultTargetBranch, repo.DefaultBranch)
|
||||||
|
}
|
||||||
32
models/repo/pull_request_default_test.go
Normal file
32
models/repo/pull_request_default_test.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/unit"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDefaultTargetBranchSelection(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
ctx := t.Context()
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1})
|
||||||
|
|
||||||
|
assert.Equal(t, repo.DefaultBranch, repo.GetPullRequestTargetBranch(ctx))
|
||||||
|
|
||||||
|
repo.Units = nil
|
||||||
|
prUnit, err := repo.GetUnit(ctx, unit.TypePullRequests)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
prConfig := prUnit.PullRequestsConfig()
|
||||||
|
prConfig.DefaultTargetBranch = "branch2"
|
||||||
|
prUnit.Config = prConfig
|
||||||
|
assert.NoError(t, UpdateRepoUnit(ctx, prUnit))
|
||||||
|
repo.Units = nil
|
||||||
|
assert.Equal(t, "branch2", repo.GetPullRequestTargetBranch(ctx))
|
||||||
|
}
|
||||||
@@ -613,16 +613,13 @@ func (repo *Repository) ComposeCompareURL(oldCommitID, newCommitID string) strin
|
|||||||
return fmt.Sprintf("%s/%s/compare/%s...%s", url.PathEscape(repo.OwnerName), url.PathEscape(repo.Name), util.PathEscapeSegments(oldCommitID), util.PathEscapeSegments(newCommitID))
|
return fmt.Sprintf("%s/%s/compare/%s...%s", url.PathEscape(repo.OwnerName), url.PathEscape(repo.Name), util.PathEscapeSegments(oldCommitID), util.PathEscapeSegments(newCommitID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) ComposeBranchCompareURL(baseRepo *Repository, branchName string) string {
|
func (repo *Repository) ComposeBranchCompareURL(baseRepo *Repository, baseBranch, branchName string) string {
|
||||||
if baseRepo == nil {
|
|
||||||
baseRepo = repo
|
|
||||||
}
|
|
||||||
var cmpBranchEscaped string
|
var cmpBranchEscaped string
|
||||||
if repo.ID != baseRepo.ID {
|
if repo.ID != baseRepo.ID {
|
||||||
cmpBranchEscaped = fmt.Sprintf("%s/%s:", url.PathEscape(repo.OwnerName), url.PathEscape(repo.Name))
|
cmpBranchEscaped = fmt.Sprintf("%s/%s:", url.PathEscape(repo.OwnerName), url.PathEscape(repo.Name))
|
||||||
}
|
}
|
||||||
cmpBranchEscaped = fmt.Sprintf("%s%s", cmpBranchEscaped, util.PathEscapeSegments(branchName))
|
cmpBranchEscaped = fmt.Sprintf("%s%s", cmpBranchEscaped, util.PathEscapeSegments(branchName))
|
||||||
return fmt.Sprintf("%s/compare/%s...%s", baseRepo.Link(), util.PathEscapeSegments(baseRepo.DefaultBranch), cmpBranchEscaped)
|
return fmt.Sprintf("%s/compare/%s...%s", baseRepo.Link(), util.PathEscapeSegments(baseBranch), cmpBranchEscaped)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsOwnedBy returns true when user owns this repository
|
// IsOwnedBy returns true when user owns this repository
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ type PullRequestsConfig struct {
|
|||||||
DefaultDeleteBranchAfterMerge bool
|
DefaultDeleteBranchAfterMerge bool
|
||||||
DefaultMergeStyle MergeStyle
|
DefaultMergeStyle MergeStyle
|
||||||
DefaultAllowMaintainerEdit bool
|
DefaultAllowMaintainerEdit bool
|
||||||
|
DefaultTargetBranch string
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromDB fills up a PullRequestsConfig from serialized format.
|
// FromDB fills up a PullRequestsConfig from serialized format.
|
||||||
|
|||||||
@@ -58,26 +58,27 @@ type Repository struct {
|
|||||||
Fork bool `json:"fork"`
|
Fork bool `json:"fork"`
|
||||||
Template bool `json:"template"`
|
Template bool `json:"template"`
|
||||||
// the original repository if this repository is a fork, otherwise null
|
// the original repository if this repository is a fork, otherwise null
|
||||||
Parent *Repository `json:"parent,omitempty"`
|
Parent *Repository `json:"parent,omitempty"`
|
||||||
Mirror bool `json:"mirror"`
|
Mirror bool `json:"mirror"`
|
||||||
Size int `json:"size"`
|
Size int `json:"size"`
|
||||||
Language string `json:"language"`
|
Language string `json:"language"`
|
||||||
LanguagesURL string `json:"languages_url"`
|
LanguagesURL string `json:"languages_url"`
|
||||||
HTMLURL string `json:"html_url"`
|
HTMLURL string `json:"html_url"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Link string `json:"link"`
|
Link string `json:"link"`
|
||||||
SSHURL string `json:"ssh_url"`
|
SSHURL string `json:"ssh_url"`
|
||||||
CloneURL string `json:"clone_url"`
|
CloneURL string `json:"clone_url"`
|
||||||
OriginalURL string `json:"original_url"`
|
OriginalURL string `json:"original_url"`
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
Stars int `json:"stars_count"`
|
Stars int `json:"stars_count"`
|
||||||
Forks int `json:"forks_count"`
|
Forks int `json:"forks_count"`
|
||||||
Watchers int `json:"watchers_count"`
|
Watchers int `json:"watchers_count"`
|
||||||
OpenIssues int `json:"open_issues_count"`
|
OpenIssues int `json:"open_issues_count"`
|
||||||
OpenPulls int `json:"open_pr_counter"`
|
OpenPulls int `json:"open_pr_counter"`
|
||||||
Releases int `json:"release_counter"`
|
Releases int `json:"release_counter"`
|
||||||
DefaultBranch string `json:"default_branch"`
|
DefaultBranch string `json:"default_branch"`
|
||||||
Archived bool `json:"archived"`
|
DefaultTargetBranch string `json:"default_target_branch,omitempty"`
|
||||||
|
Archived bool `json:"archived"`
|
||||||
// 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
|
||||||
|
|||||||
@@ -2124,6 +2124,8 @@
|
|||||||
"repo.settings.pulls.ignore_whitespace": "Ignore Whitespace for Conflicts",
|
"repo.settings.pulls.ignore_whitespace": "Ignore Whitespace for Conflicts",
|
||||||
"repo.settings.pulls.enable_autodetect_manual_merge": "Enable autodetect manual merge (Note: In some special cases, misjudgments can occur)",
|
"repo.settings.pulls.enable_autodetect_manual_merge": "Enable autodetect manual merge (Note: In some special cases, misjudgments can occur)",
|
||||||
"repo.settings.pulls.allow_rebase_update": "Enable updating pull request branch by rebase",
|
"repo.settings.pulls.allow_rebase_update": "Enable updating pull request branch by rebase",
|
||||||
|
"repo.settings.pulls.default_target_branch": "Default target branch for new pull requests",
|
||||||
|
"repo.settings.pulls.default_target_branch_default": "Default branch (%s)",
|
||||||
"repo.settings.pulls.default_delete_branch_after_merge": "Delete pull request branch after merge by default",
|
"repo.settings.pulls.default_delete_branch_after_merge": "Delete pull request branch after merge by default",
|
||||||
"repo.settings.pulls.default_allow_edits_from_maintainers": "Allow edits from maintainers by default",
|
"repo.settings.pulls.default_allow_edits_from_maintainers": "Allow edits from maintainers by default",
|
||||||
"repo.settings.releases_desc": "Enable Repository Releases",
|
"repo.settings.releases_desc": "Enable Repository Releases",
|
||||||
@@ -2436,9 +2438,10 @@
|
|||||||
"repo.settings.block_outdated_branch_desc": "Merging will not be possible when head branch is behind base branch.",
|
"repo.settings.block_outdated_branch_desc": "Merging will not be possible when head branch is behind base branch.",
|
||||||
"repo.settings.block_admin_merge_override": "Administrators must follow branch protection rules",
|
"repo.settings.block_admin_merge_override": "Administrators must follow branch protection rules",
|
||||||
"repo.settings.block_admin_merge_override_desc": "Administrators must follow branch protection rules and cannot circumvent it.",
|
"repo.settings.block_admin_merge_override_desc": "Administrators must follow branch protection rules and cannot circumvent it.",
|
||||||
"repo.settings.default_branch_desc": "Select a default repository branch for pull requests and code commits:",
|
"repo.settings.default_branch_desc": "Select a default branch for code commits.",
|
||||||
|
"repo.settings.default_target_branch_desc": "Pull requests can use different default target branch if it is set in the Pull Requests section of Repository Advance Settings.",
|
||||||
"repo.settings.merge_style_desc": "Merge Styles",
|
"repo.settings.merge_style_desc": "Merge Styles",
|
||||||
"repo.settings.default_merge_style_desc": "Default Merge Style",
|
"repo.settings.default_merge_style_desc": "Default merge style",
|
||||||
"repo.settings.choose_branch": "Choose a branch…",
|
"repo.settings.choose_branch": "Choose a branch…",
|
||||||
"repo.settings.no_protected_branch": "There are no protected branches.",
|
"repo.settings.no_protected_branch": "There are no protected branches.",
|
||||||
"repo.settings.edit_protected_branch": "Edit",
|
"repo.settings.edit_protected_branch": "Edit",
|
||||||
@@ -2650,7 +2653,7 @@
|
|||||||
"repo.branch.restore_success": "Branch \"%s\" has been restored.",
|
"repo.branch.restore_success": "Branch \"%s\" has been restored.",
|
||||||
"repo.branch.restore_failed": "Failed to restore branch \"%s\".",
|
"repo.branch.restore_failed": "Failed to restore branch \"%s\".",
|
||||||
"repo.branch.protected_deletion_failed": "Branch \"%s\" is protected. It cannot be deleted.",
|
"repo.branch.protected_deletion_failed": "Branch \"%s\" is protected. It cannot be deleted.",
|
||||||
"repo.branch.default_deletion_failed": "Branch \"%s\" is the default branch. It cannot be deleted.",
|
"repo.branch.default_deletion_failed": "Branch \"%s\" is the default or pull request target branch. It cannot be deleted.",
|
||||||
"repo.branch.default_branch_not_exist": "Default branch \"%s\" does not exist.",
|
"repo.branch.default_branch_not_exist": "Default branch \"%s\" does not exist.",
|
||||||
"repo.branch.restore": "Restore Branch \"%s\"",
|
"repo.branch.restore": "Restore Branch \"%s\"",
|
||||||
"repo.branch.download": "Download Branch \"%s\"",
|
"repo.branch.download": "Download Branch \"%s\"",
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ func DeleteBranch(ctx *context.APIContext) {
|
|||||||
case git.IsErrBranchNotExist(err):
|
case git.IsErrBranchNotExist(err):
|
||||||
ctx.APIErrorNotFound(err)
|
ctx.APIErrorNotFound(err)
|
||||||
case errors.Is(err, repo_service.ErrBranchIsDefault):
|
case errors.Is(err, repo_service.ErrBranchIsDefault):
|
||||||
ctx.APIError(http.StatusForbidden, errors.New("can not delete default branch"))
|
ctx.APIError(http.StatusForbidden, errors.New("can not delete default or pull request target branch"))
|
||||||
case errors.Is(err, git_model.ErrBranchIsProtected):
|
case errors.Is(err, git_model.ErrBranchIsProtected):
|
||||||
ctx.APIError(http.StatusForbidden, errors.New("branch protected"))
|
ctx.APIError(http.StatusForbidden, errors.New("branch protected"))
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1138,7 +1138,7 @@ func parseCompareInfo(ctx *context.APIContext, compareParam string) (result *git
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
baseRef := ctx.Repo.GitRepo.UnstableGuessRefByShortName(util.IfZero(compareReq.BaseOriRef, baseRepo.DefaultBranch))
|
baseRef := ctx.Repo.GitRepo.UnstableGuessRefByShortName(util.IfZero(compareReq.BaseOriRef, baseRepo.GetPullRequestTargetBranch(ctx)))
|
||||||
headRef := headGitRepo.UnstableGuessRefByShortName(util.IfZero(compareReq.HeadOriRef, headRepo.DefaultBranch))
|
headRef := headGitRepo.UnstableGuessRefByShortName(util.IfZero(compareReq.HeadOriRef, headRepo.DefaultBranch))
|
||||||
|
|
||||||
log.Trace("Repo path: %q, base ref: %q->%q, head ref: %q->%q", ctx.Repo.Repository.RelativePath(), compareReq.BaseOriRef, baseRef, compareReq.HeadOriRef, headRef)
|
log.Trace("Repo path: %q, base ref: %q->%q, head ref: %q->%q", ctx.Repo.Repository.RelativePath(), compareReq.BaseOriRef, baseRef, compareReq.HeadOriRef, headRef)
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ func Branches(ctx *context.Context) {
|
|||||||
ctx.Data["AllowsPulls"] = ctx.Repo.Repository.AllowsPulls(ctx)
|
ctx.Data["AllowsPulls"] = ctx.Repo.Repository.AllowsPulls(ctx)
|
||||||
ctx.Data["IsWriter"] = ctx.Repo.CanWrite(unit.TypeCode)
|
ctx.Data["IsWriter"] = ctx.Repo.CanWrite(unit.TypeCode)
|
||||||
ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
|
ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
|
||||||
|
// TODO: Can be replaced by ctx.Repo.PullRequestCtx.CanCreateNewPull()
|
||||||
ctx.Data["CanPull"] = ctx.Repo.CanWrite(unit.TypeCode) ||
|
ctx.Data["CanPull"] = ctx.Repo.CanWrite(unit.TypeCode) ||
|
||||||
(ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID))
|
(ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID))
|
||||||
ctx.Data["PageIsViewCode"] = true
|
ctx.Data["PageIsViewCode"] = true
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ func ParseCompareInfo(ctx *context.Context) *git_service.CompareInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4 get base and head refs
|
// 4 get base and head refs
|
||||||
baseRefName := util.IfZero(compareReq.BaseOriRef, baseRepo.DefaultBranch)
|
baseRefName := util.IfZero(compareReq.BaseOriRef, baseRepo.GetPullRequestTargetBranch(ctx))
|
||||||
headRefName := util.IfZero(compareReq.HeadOriRef, headRepo.DefaultBranch)
|
headRefName := util.IfZero(compareReq.HeadOriRef, headRepo.DefaultBranch)
|
||||||
|
|
||||||
baseRef := ctx.Repo.GitRepo.UnstableGuessRefByShortName(baseRefName)
|
baseRef := ctx.Repo.GitRepo.UnstableGuessRefByShortName(baseRefName)
|
||||||
@@ -276,10 +276,10 @@ func ParseCompareInfo(ctx *context.Context) *git_service.CompareInfo {
|
|||||||
ctx.Data["BaseBranch"] = baseRef.ShortName() // for legacy templates
|
ctx.Data["BaseBranch"] = baseRef.ShortName() // for legacy templates
|
||||||
ctx.Data["HeadUser"] = headOwner
|
ctx.Data["HeadUser"] = headOwner
|
||||||
ctx.Data["HeadBranch"] = headRef.ShortName() // for legacy templates
|
ctx.Data["HeadBranch"] = headRef.ShortName() // for legacy templates
|
||||||
ctx.Repo.PullRequest.SameRepo = isSameRepo
|
|
||||||
|
|
||||||
ctx.Data["IsPull"] = true
|
ctx.Data["IsPull"] = true
|
||||||
|
|
||||||
|
context.InitRepoPullRequestCtx(ctx, baseRepo, headRepo)
|
||||||
|
|
||||||
// The current base and head repositories and branches may not
|
// The current base and head repositories and branches may not
|
||||||
// actually be the intended branches that the user wants to
|
// actually be the intended branches that the user wants to
|
||||||
// create a pull-request from - but also determining the head
|
// create a pull-request from - but also determining the head
|
||||||
|
|||||||
@@ -109,11 +109,6 @@ func MustAllowPulls(ctx *context.Context) {
|
|||||||
ctx.NotFound(nil)
|
ctx.NotFound(nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// User can send pull request if owns a forked repository.
|
|
||||||
if ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) {
|
|
||||||
ctx.Repo.PullRequest.Allowed = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func retrieveProjectsInternal(ctx *context.Context, repo *repo_model.Repository) (open, closed []*project_model.Project) {
|
func retrieveProjectsInternal(ctx *context.Context, repo *repo_model.Repository) (open, closed []*project_model.Project) {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/modules/validation"
|
"code.gitea.io/gitea/modules/validation"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
|
repo_router "code.gitea.io/gitea/routers/web/repo"
|
||||||
actions_service "code.gitea.io/gitea/services/actions"
|
actions_service "code.gitea.io/gitea/services/actions"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
@@ -88,6 +89,11 @@ func SettingsCtxData(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["PushMirrors"] = pushMirrors
|
ctx.Data["PushMirrors"] = pushMirrors
|
||||||
|
|
||||||
|
repo_router.PrepareBranchList(ctx)
|
||||||
|
if ctx.Written() {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings show a repository's settings page
|
// Settings show a repository's settings page
|
||||||
@@ -622,6 +628,7 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
|
|||||||
DefaultDeleteBranchAfterMerge: form.DefaultDeleteBranchAfterMerge,
|
DefaultDeleteBranchAfterMerge: form.DefaultDeleteBranchAfterMerge,
|
||||||
DefaultMergeStyle: repo_model.MergeStyle(form.PullsDefaultMergeStyle),
|
DefaultMergeStyle: repo_model.MergeStyle(form.PullsDefaultMergeStyle),
|
||||||
DefaultAllowMaintainerEdit: form.DefaultAllowMaintainerEdit,
|
DefaultAllowMaintainerEdit: form.DefaultAllowMaintainerEdit,
|
||||||
|
DefaultTargetBranch: strings.TrimSpace(form.DefaultTargetBranch),
|
||||||
}))
|
}))
|
||||||
} else if !unit_model.TypePullRequests.UnitGlobalDisabled() {
|
} else if !unit_model.TypePullRequests.UnitGlobalDisabled() {
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePullRequests)
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePullRequests)
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ func APIContexter() func(http.Handler) http.Handler {
|
|||||||
ctx := &APIContext{
|
ctx := &APIContext{
|
||||||
Base: base,
|
Base: base,
|
||||||
Cache: cache.GetCache(),
|
Cache: cache.GetCache(),
|
||||||
Repo: &Repository{PullRequest: &PullRequest{}},
|
Repo: &Repository{},
|
||||||
Org: &APIOrganization{},
|
Org: &APIOrganization{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ func NewWebContext(base *Base, render Render, session session.Store) *Context {
|
|||||||
|
|
||||||
Cache: cache.GetCache(),
|
Cache: cache.GetCache(),
|
||||||
Link: setting.AppSubURL + strings.TrimSuffix(base.Req.URL.EscapedPath(), "/"),
|
Link: setting.AppSubURL + strings.TrimSuffix(base.Req.URL.EscapedPath(), "/"),
|
||||||
Repo: &Repository{PullRequest: &PullRequest{}},
|
Repo: &Repository{},
|
||||||
Org: &Organization{},
|
Org: &Organization{},
|
||||||
}
|
}
|
||||||
ctx.TemplateContext = NewTemplateContextForWeb(ctx)
|
ctx.TemplateContext = NewTemplateContextForWeb(ctx)
|
||||||
|
|||||||
@@ -37,11 +37,46 @@ import (
|
|||||||
"github.com/editorconfig/editorconfig-core-go/v2"
|
"github.com/editorconfig/editorconfig-core-go/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PullRequest contains information to make a pull request
|
// PullRequestContext contains context information for making a new pull request
|
||||||
type PullRequest struct {
|
type PullRequestContext struct {
|
||||||
BaseRepo *repo_model.Repository
|
ctx *Context
|
||||||
Allowed bool // it only used by the web tmpl: "PullRequestCtx.Allowed"
|
|
||||||
SameRepo bool // it only used by the web tmpl: "PullRequestCtx.SameRepo"
|
baseRepo, headRepo *repo_model.Repository
|
||||||
|
|
||||||
|
canCreateNewPull *bool
|
||||||
|
defaultTargetBranch *string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (prc *PullRequestContext) SameRepo() bool {
|
||||||
|
return prc.baseRepo != nil && prc.headRepo != nil && prc.baseRepo.ID == prc.headRepo.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (prc *PullRequestContext) CanCreateNewPull() bool {
|
||||||
|
if prc.canCreateNewPull != nil {
|
||||||
|
return *prc.canCreateNewPull
|
||||||
|
}
|
||||||
|
ctx := prc.ctx
|
||||||
|
// People who have push access or have forked repository can propose a new pull request.
|
||||||
|
can := prc.baseRepo.CanContentChange() &&
|
||||||
|
(ctx.Repo.CanWrite(unit_model.TypeCode) || (ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)))
|
||||||
|
prc.canCreateNewPull = &can
|
||||||
|
return can
|
||||||
|
}
|
||||||
|
|
||||||
|
func (prc *PullRequestContext) MakeDefaultCompareLink(headBranch string) string {
|
||||||
|
return prc.baseRepo.Link() + "/compare/" +
|
||||||
|
util.PathEscapeSegments(prc.DefaultTargetBranch()) + "..." +
|
||||||
|
util.Iif(prc.SameRepo(), "", util.PathEscapeSegments(prc.headRepo.OwnerName)+":") +
|
||||||
|
util.PathEscapeSegments(headBranch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (prc *PullRequestContext) DefaultTargetBranch() string {
|
||||||
|
if prc.defaultTargetBranch != nil {
|
||||||
|
return *prc.defaultTargetBranch
|
||||||
|
}
|
||||||
|
branchName := prc.baseRepo.GetPullRequestTargetBranch(prc.ctx)
|
||||||
|
prc.defaultTargetBranch = &branchName
|
||||||
|
return branchName
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repository contains information to operate a repository
|
// Repository contains information to operate a repository
|
||||||
@@ -64,7 +99,7 @@ type Repository struct {
|
|||||||
CommitID string
|
CommitID string
|
||||||
CommitsCount int64
|
CommitsCount int64
|
||||||
|
|
||||||
PullRequest *PullRequest
|
PullRequestCtx *PullRequestContext
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanWriteToBranch checks if the branch is writable by the user
|
// CanWriteToBranch checks if the branch is writable by the user
|
||||||
@@ -418,6 +453,12 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) {
|
|||||||
ctx.Data["IsEmptyRepo"] = ctx.Repo.Repository.IsEmpty
|
ctx.Data["IsEmptyRepo"] = ctx.Repo.Repository.IsEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func InitRepoPullRequestCtx(ctx *Context, base, head *repo_model.Repository) {
|
||||||
|
ctx.Repo.PullRequestCtx = &PullRequestContext{ctx: ctx}
|
||||||
|
ctx.Repo.PullRequestCtx.baseRepo, ctx.Repo.PullRequestCtx.headRepo = base, head
|
||||||
|
ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequestCtx
|
||||||
|
}
|
||||||
|
|
||||||
// RepoAssignment returns a middleware to handle repository assignment
|
// RepoAssignment returns a middleware to handle repository assignment
|
||||||
func RepoAssignment(ctx *Context) {
|
func RepoAssignment(ctx *Context) {
|
||||||
if ctx.Data["Repository"] != nil {
|
if ctx.Data["Repository"] != nil {
|
||||||
@@ -666,28 +707,16 @@ func RepoAssignment(ctx *Context) {
|
|||||||
|
|
||||||
ctx.Data["BranchesCount"] = branchesTotal
|
ctx.Data["BranchesCount"] = branchesTotal
|
||||||
|
|
||||||
// People who have push access or have forked repository can propose a new pull request.
|
// Pull request is allowed if this is a fork repository, and base repository accepts pull requests.
|
||||||
canPush := ctx.Repo.CanWrite(unit_model.TypeCode) ||
|
|
||||||
(ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID))
|
|
||||||
canCompare := false
|
|
||||||
|
|
||||||
// Pull request is allowed if this is a fork repository
|
|
||||||
// and base repository accepts pull requests.
|
|
||||||
if repo.BaseRepo != nil && repo.BaseRepo.AllowsPulls(ctx) {
|
if repo.BaseRepo != nil && repo.BaseRepo.AllowsPulls(ctx) {
|
||||||
canCompare = true
|
// TODO: this (and below) "BaseRepo" var is not clear and should be removed in the future
|
||||||
ctx.Data["BaseRepo"] = repo.BaseRepo
|
ctx.Data["BaseRepo"] = repo.BaseRepo
|
||||||
ctx.Repo.PullRequest.BaseRepo = repo.BaseRepo
|
InitRepoPullRequestCtx(ctx, repo.BaseRepo, repo)
|
||||||
ctx.Repo.PullRequest.Allowed = canPush
|
|
||||||
} else if repo.AllowsPulls(ctx) {
|
} else if repo.AllowsPulls(ctx) {
|
||||||
// Or, this is repository accepts pull requests between branches.
|
// Or, this is repository accepts pull requests between branches.
|
||||||
canCompare = true
|
|
||||||
ctx.Data["BaseRepo"] = repo
|
ctx.Data["BaseRepo"] = repo
|
||||||
ctx.Repo.PullRequest.BaseRepo = repo
|
InitRepoPullRequestCtx(ctx, repo, repo)
|
||||||
ctx.Repo.PullRequest.Allowed = canPush
|
|
||||||
ctx.Repo.PullRequest.SameRepo = true
|
|
||||||
}
|
}
|
||||||
ctx.Data["CanCompareOrPull"] = canCompare
|
|
||||||
ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest
|
|
||||||
|
|
||||||
if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer {
|
if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer {
|
||||||
repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
|
repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
|
|||||||
defaultDeleteBranchAfterMerge := false
|
defaultDeleteBranchAfterMerge := false
|
||||||
defaultMergeStyle := repo_model.MergeStyleMerge
|
defaultMergeStyle := repo_model.MergeStyleMerge
|
||||||
defaultAllowMaintainerEdit := false
|
defaultAllowMaintainerEdit := false
|
||||||
|
defaultTargetBranch := ""
|
||||||
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()
|
||||||
hasPullRequests = true
|
hasPullRequests = true
|
||||||
@@ -118,6 +119,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
|
|||||||
defaultDeleteBranchAfterMerge = config.DefaultDeleteBranchAfterMerge
|
defaultDeleteBranchAfterMerge = config.DefaultDeleteBranchAfterMerge
|
||||||
defaultMergeStyle = config.GetDefaultMergeStyle()
|
defaultMergeStyle = config.GetDefaultMergeStyle()
|
||||||
defaultAllowMaintainerEdit = config.DefaultAllowMaintainerEdit
|
defaultAllowMaintainerEdit = config.DefaultAllowMaintainerEdit
|
||||||
|
defaultTargetBranch = config.DefaultTargetBranch
|
||||||
}
|
}
|
||||||
hasProjects := false
|
hasProjects := false
|
||||||
projectsMode := repo_model.ProjectsModeAll
|
projectsMode := repo_model.ProjectsModeAll
|
||||||
@@ -235,6 +237,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
|
|||||||
DefaultDeleteBranchAfterMerge: defaultDeleteBranchAfterMerge,
|
DefaultDeleteBranchAfterMerge: defaultDeleteBranchAfterMerge,
|
||||||
DefaultMergeStyle: string(defaultMergeStyle),
|
DefaultMergeStyle: string(defaultMergeStyle),
|
||||||
DefaultAllowMaintainerEdit: defaultAllowMaintainerEdit,
|
DefaultAllowMaintainerEdit: defaultAllowMaintainerEdit,
|
||||||
|
DefaultTargetBranch: defaultTargetBranch,
|
||||||
AvatarURL: repo.AvatarLink(ctx),
|
AvatarURL: repo.AvatarLink(ctx),
|
||||||
Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
|
Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
|
||||||
MirrorInterval: mirrorInterval,
|
MirrorInterval: mirrorInterval,
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ type RepoSettingForm struct {
|
|||||||
PullsAllowRebaseUpdate bool
|
PullsAllowRebaseUpdate bool
|
||||||
DefaultDeleteBranchAfterMerge bool
|
DefaultDeleteBranchAfterMerge bool
|
||||||
DefaultAllowMaintainerEdit bool
|
DefaultAllowMaintainerEdit bool
|
||||||
|
DefaultTargetBranch string
|
||||||
EnableTimetracker bool
|
EnableTimetracker bool
|
||||||
AllowOnlyContributorsToTrackTime bool
|
AllowOnlyContributorsToTrackTime bool
|
||||||
EnableIssueDependencies bool
|
EnableIssueDependencies bool
|
||||||
|
|||||||
@@ -547,10 +547,11 @@ func UpdateBranch(ctx context.Context, repo *repo_model.Repository, gitRepo *git
|
|||||||
return gitrepo.Push(ctx, repo, repo, pushOpts)
|
return gitrepo.Push(ctx, repo, repo, pushOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ErrBranchIsDefault = util.ErrorWrap(util.ErrPermissionDenied, "branch is default")
|
var ErrBranchIsDefault = util.ErrorWrap(util.ErrPermissionDenied, "branch is default or pull request target")
|
||||||
|
|
||||||
func CanDeleteBranch(ctx context.Context, repo *repo_model.Repository, branchName string, doer *user_model.User) error {
|
func CanDeleteBranch(ctx context.Context, repo *repo_model.Repository, branchName string, doer *user_model.User) error {
|
||||||
if branchName == repo.DefaultBranch {
|
unitPRConfig := repo.MustGetUnit(ctx, unit.TypePullRequests).PullRequestsConfig()
|
||||||
|
if branchName == repo.DefaultBranch || branchName == unitPRConfig.DefaultTargetBranch {
|
||||||
return ErrBranchIsDefault
|
return ErrBranchIsDefault
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,14 +133,14 @@
|
|||||||
<span class="ui orange large label" data-tooltip-content="{{ctx.Locale.Tr "repo.branch.included_desc"}}">
|
<span class="ui orange large label" data-tooltip-content="{{ctx.Locale.Tr "repo.branch.included_desc"}}">
|
||||||
{{svg "octicon-git-pull-request"}} {{ctx.Locale.Tr "repo.branch.included"}}
|
{{svg "octicon-git-pull-request"}} {{ctx.Locale.Tr "repo.branch.included"}}
|
||||||
</span>
|
</span>
|
||||||
{{else if and (not .DBBranch.IsDeleted) $.AllowsPulls (gt .CommitsAhead 0)}}
|
{{else if and (not .DBBranch.IsDeleted) $.AllowsPulls (gt .CommitsAhead 0)}}
|
||||||
<a href="{{$.RepoLink}}/compare/{{PathEscapeSegments $.DefaultBranchBranch.DBBranch.Name}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{PathEscape $.Owner.Name}}:{{end}}{{PathEscapeSegments .DBBranch.Name}}?expand=1">
|
<a href="{{$.PullRequestCtx.MakeDefaultCompareLink .DBBranch.Name}}?expand=1">
|
||||||
<button id="new-pull-request" class="ui compact basic button tw-mr-0">{{if $.CanPull}}{{ctx.Locale.Tr "repo.pulls.compare_changes"}}{{else}}{{ctx.Locale.Tr "action.compare_branch"}}{{end}}</button>
|
<button id="new-pull-request" class="ui compact basic button tw-mr-0">{{if $.CanPull}}{{ctx.Locale.Tr "repo.pulls.compare_changes"}}{{else}}{{ctx.Locale.Tr "action.compare_branch"}}{{end}}</button>
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else if and .LatestPullRequest.HasMerged .MergeMovedOn}}
|
{{else if and .LatestPullRequest.HasMerged .MergeMovedOn}}
|
||||||
{{if and (not .DBBranch.IsDeleted) $.AllowsPulls (gt .CommitsAhead 0)}}
|
{{if and (not .DBBranch.IsDeleted) $.AllowsPulls (gt .CommitsAhead 0)}}
|
||||||
<a href="{{$.RepoLink}}/compare/{{PathEscapeSegments $.DefaultBranchBranch.DBBranch.Name}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{PathEscape $.Owner.Name}}:{{end}}{{PathEscapeSegments .DBBranch.Name}}?expand=1">
|
<a href="{{$.PullRequestCtx.MakeDefaultCompareLink .DBBranch.Name}}?expand=1">
|
||||||
<button id="new-pull-request" class="ui compact basic button tw-mr-0">{{if $.CanPull}}{{ctx.Locale.Tr "repo.pulls.compare_changes"}}{{else}}{{ctx.Locale.Tr "action.compare_branch"}}{{end}}</button>
|
<button id="new-pull-request" class="ui compact basic button tw-mr-0">{{if $.CanPull}}{{ctx.Locale.Tr "repo.pulls.compare_changes"}}{{else}}{{ctx.Locale.Tr "action.compare_branch"}}{{end}}</button>
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@@ -24,11 +24,12 @@
|
|||||||
{{if .PageIsIssueList}}
|
{{if .PageIsIssueList}}
|
||||||
<a class="ui small primary button issue-list-new" href="{{.RepoLink}}/issues/new{{if .NewIssueChooseTemplate}}/choose{{end}}">{{ctx.Locale.Tr "repo.issues.new"}}</a>
|
<a class="ui small primary button issue-list-new" href="{{.RepoLink}}/issues/new{{if .NewIssueChooseTemplate}}/choose{{end}}">{{ctx.Locale.Tr "repo.issues.new"}}</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a class="ui small primary button new-pr-button issue-list-new{{if not .PullRequestCtx.Allowed}} disabled{{end}}" href="{{if .PullRequestCtx.Allowed}}{{.Repository.Link}}/compare/{{.Repository.DefaultBranch | PathEscapeSegments}}...{{if ne .Repository.Owner.Name .PullRequestCtx.BaseRepo.Owner.Name}}{{PathEscape .Repository.Owner.Name}}:{{end}}{{.Repository.DefaultBranch | PathEscapeSegments}}{{end}}">{{ctx.Locale.Tr "repo.pulls.new"}}</a>
|
<a class="ui small primary button new-pr-button issue-list-new {{if not .PullRequestCtx.CanCreateNewPull}}disabled{{end}}" href="{{.PullRequestCtx.MakeDefaultCompareLink .Repository.DefaultBranch}}">{{ctx.Locale.Tr "repo.pulls.new"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
{{/* archived, view compare page only */}}
|
||||||
{{if not .PageIsIssueList}}
|
{{if not .PageIsIssueList}}
|
||||||
<a class="ui small primary small button issue-list-new{{if not .PullRequestCtx.Allowed}} disabled{{end}}" href="{{if .PullRequestCtx.Allowed}}{{.PullRequestCtx.BaseRepo.Link}}/compare/{{.PullRequestCtx.BaseRepo.DefaultBranch | PathEscapeSegments}}...{{if ne .Repository.Owner.Name .PullRequestCtx.BaseRepo.Owner.Name}}{{PathEscape .Repository.Owner.Name}}:{{end}}{{.Repository.DefaultBranch | PathEscapeSegments}}{{end}}">{{ctx.Locale.Tr "action.compare_commits_general"}}</a>
|
<a class="ui small primary small button issue-list-new" href="{{.PullRequestCtx.MakeDefaultCompareLink .Repository.DefaultBranch}}">{{ctx.Locale.Tr "action.compare_commits_general"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,22 +9,23 @@
|
|||||||
{{ctx.Locale.Tr "repo.default_branch"}}
|
{{ctx.Locale.Tr "repo.default_branch"}}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<p>
|
<p>{{ctx.Locale.Tr "repo.settings.default_branch_desc"}}</p>
|
||||||
{{ctx.Locale.Tr "repo.settings.default_branch_desc"}}
|
<form class="ui form" action="{{.Link}}" method="post">
|
||||||
</p>
|
|
||||||
<form class="tw-flex" action="{{.Link}}" method="post">
|
|
||||||
<input type="hidden" name="action" value="default_branch">
|
<input type="hidden" name="action" value="default_branch">
|
||||||
<div class="ui dropdown selection search tw-flex-1 tw-mr-2 tw-max-w-96">
|
<div class="flex-text-block">
|
||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
<div class="ui dropdown selection search tw-flex-1 tw-mr-2 tw-max-w-96">
|
||||||
<input type="hidden" name="branch" value="{{.Repository.DefaultBranch}}">
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
<div class="default text">{{.Repository.DefaultBranch}}</div>
|
<input type="hidden" name="branch" value="{{.Repository.DefaultBranch}}">
|
||||||
<div class="menu">
|
<div class="default text">{{.Repository.DefaultBranch}}</div>
|
||||||
{{range .Branches}}
|
<div class="menu">
|
||||||
<div class="item" data-value="{{.}}">{{.}}</div>
|
{{range .Branches}}
|
||||||
{{end}}
|
<div class="item" data-value="{{.}}">{{.}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<button class="ui primary button"{{if .Repository.IsEmpty}} disabled{{end}}>{{ctx.Locale.Tr "repo.settings.branches.update_default_branch"}}</button>
|
||||||
</div>
|
</div>
|
||||||
<button class="ui primary button"{{if .Repository.IsEmpty}} disabled{{end}}>{{ctx.Locale.Tr "repo.settings.branches.update_default_branch"}}</button>
|
<div class="help tw-mt-4 tw-p-0">{{ctx.Locale.Tr "repo.settings.default_target_branch_desc"}}</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -287,6 +287,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{/* FIXME: need to split the "Advance Settings" by units, there are too many options here */}}
|
||||||
<h4 class="ui top attached header">
|
<h4 class="ui top attached header">
|
||||||
{{ctx.Locale.Tr "repo.settings.advanced_settings"}}
|
{{ctx.Locale.Tr "repo.settings.advanced_settings"}}
|
||||||
</h4>
|
</h4>
|
||||||
@@ -594,6 +595,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.pulls.default_target_branch"}}</label>
|
||||||
|
<div class="ui search selection dropdown">
|
||||||
|
<input type="hidden" name="default_target_branch" value="{{$prUnit.PullRequestsConfig.DefaultTargetBranch}}">
|
||||||
|
<div class="default text"></div>
|
||||||
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
|
<div class="menu">
|
||||||
|
<div class="item" data-value="">{{ctx.Locale.Tr "repo.settings.pulls.default_target_branch_default" $.Repository.DefaultBranch}}</div>
|
||||||
|
{{range $branchName := $.Branches}}
|
||||||
|
<div class="item" data-value="{{$branchName}}">{{$branchName}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input name="default_allow_maintainer_edit" type="checkbox" {{if or (not $pullRequestEnabled) ($prUnit.PullRequestsConfig.DefaultAllowMaintainerEdit)}}checked{{end}}>
|
<input name="default_allow_maintainer_edit" type="checkbox" {{if or (not $pullRequestEnabled) ($prUnit.PullRequestsConfig.DefaultAllowMaintainerEdit)}}checked{{end}}>
|
||||||
|
|||||||
@@ -20,15 +20,10 @@
|
|||||||
"ShowViewAllRefsEntry" true
|
"ShowViewAllRefsEntry" true
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{{if and .CanCompareOrPull .RefFullName.IsBranch (not .Repository.IsArchived)}}
|
{{if and .PullRequestCtx.CanCreateNewPull .RefFullName.IsBranch}}
|
||||||
{{$cmpBranch := ""}}
|
{{$compareLink := .PullRequestCtx.MakeDefaultCompareLink .BranchName}}
|
||||||
{{if ne .Repository.ID .BaseRepo.ID}}
|
|
||||||
{{$cmpBranch = printf "%s/%s:" (.Repository.OwnerName|PathEscape) (.Repository.Name|PathEscape)}}
|
|
||||||
{{end}}
|
|
||||||
{{$cmpBranch = print $cmpBranch (.BranchName|PathEscapeSegments)}}
|
|
||||||
{{$compareLink := printf "%s/compare/%s...%s" .BaseRepo.Link (.BaseRepo.DefaultBranch|PathEscapeSegments) $cmpBranch}}
|
|
||||||
<a id="new-pull-request" role="button" class="ui compact basic button" href="{{QueryBuild $compareLink "expand" 1}}"
|
<a id="new-pull-request" role="button" class="ui compact basic button" href="{{QueryBuild $compareLink "expand" 1}}"
|
||||||
data-tooltip-content="{{if .PullRequestCtx.Allowed}}{{ctx.Locale.Tr "repo.pulls.compare_changes"}}{{else}}{{ctx.Locale.Tr "action.compare_branch"}}{{end}}">
|
data-tooltip-content="{{ctx.Locale.Tr "repo.pulls.compare_changes"}}">
|
||||||
{{svg "octicon-git-pull-request"}}
|
{{svg "octicon-git-pull-request"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
4
templates/swagger/v1_json.tmpl
generated
4
templates/swagger/v1_json.tmpl
generated
@@ -28147,6 +28147,10 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "DefaultMergeStyle"
|
"x-go-name": "DefaultMergeStyle"
|
||||||
},
|
},
|
||||||
|
"default_target_branch": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "DefaultTargetBranch"
|
||||||
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "Description"
|
"x-go-name": "Description"
|
||||||
|
|||||||
Reference in New Issue
Block a user