2017-09-14 02:16:22 -06:00
|
|
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a MIT-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package repo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2021-04-05 09:30:52 -06:00
|
|
|
"net/http"
|
2017-09-14 02:16:22 -06:00
|
|
|
"strings"
|
2019-09-17 23:39:45 -06:00
|
|
|
"time"
|
2017-09-14 02:16:22 -06:00
|
|
|
|
|
|
|
"code.gitea.io/gitea/models"
|
|
|
|
"code.gitea.io/gitea/modules/base"
|
|
|
|
"code.gitea.io/gitea/modules/context"
|
2019-03-27 03:33:00 -06:00
|
|
|
"code.gitea.io/gitea/modules/git"
|
2017-09-14 02:16:22 -06:00
|
|
|
"code.gitea.io/gitea/modules/log"
|
|
|
|
"code.gitea.io/gitea/modules/setting"
|
2021-11-16 11:18:25 -07:00
|
|
|
"code.gitea.io/gitea/modules/util"
|
2021-01-26 08:36:53 -07:00
|
|
|
"code.gitea.io/gitea/modules/web"
|
2021-04-06 13:44:05 -06:00
|
|
|
"code.gitea.io/gitea/services/forms"
|
2020-10-13 12:50:57 -06:00
|
|
|
pull_service "code.gitea.io/gitea/services/pull"
|
2021-10-08 11:03:04 -06:00
|
|
|
"code.gitea.io/gitea/services/repository"
|
2017-09-14 02:16:22 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
// ProtectedBranch render the page to protect the repository
|
|
|
|
func ProtectedBranch(ctx *context.Context) {
|
|
|
|
ctx.Data["Title"] = ctx.Tr("repo.settings")
|
|
|
|
ctx.Data["PageIsSettingsBranches"] = true
|
|
|
|
|
|
|
|
protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches()
|
|
|
|
if err != nil {
|
2018-01-10 14:34:17 -07:00
|
|
|
ctx.ServerError("GetProtectedBranches", err)
|
2017-09-14 02:16:22 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
ctx.Data["ProtectedBranches"] = protectedBranches
|
|
|
|
|
|
|
|
branches := ctx.Data["Branches"].([]string)
|
|
|
|
leftBranches := make([]string, 0, len(branches)-len(protectedBranches))
|
|
|
|
for _, b := range branches {
|
|
|
|
var protected bool
|
|
|
|
for _, pb := range protectedBranches {
|
|
|
|
if b == pb.BranchName {
|
|
|
|
protected = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !protected {
|
|
|
|
leftBranches = append(leftBranches, b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Data["LeftBranches"] = leftBranches
|
|
|
|
|
2021-04-05 09:30:52 -06:00
|
|
|
ctx.HTML(http.StatusOK, tplBranches)
|
2017-09-14 02:16:22 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// ProtectedBranchPost response for protect for a branch of a repository
|
|
|
|
func ProtectedBranchPost(ctx *context.Context) {
|
|
|
|
ctx.Data["Title"] = ctx.Tr("repo.settings")
|
|
|
|
ctx.Data["PageIsSettingsBranches"] = true
|
|
|
|
|
|
|
|
repo := ctx.Repo.Repository
|
|
|
|
|
2021-08-10 18:31:13 -06:00
|
|
|
switch ctx.FormString("action") {
|
2017-09-14 02:16:22 -06:00
|
|
|
case "default_branch":
|
|
|
|
if ctx.HasError() {
|
2021-04-05 09:30:52 -06:00
|
|
|
ctx.HTML(http.StatusOK, tplBranches)
|
2017-09-14 02:16:22 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-08-10 18:31:13 -06:00
|
|
|
branch := ctx.FormString("branch")
|
2017-09-14 02:16:22 -06:00
|
|
|
if !ctx.Repo.GitRepo.IsBranchExist(branch) {
|
|
|
|
ctx.Status(404)
|
|
|
|
return
|
|
|
|
} else if repo.DefaultBranch != branch {
|
|
|
|
repo.DefaultBranch = branch
|
|
|
|
if err := ctx.Repo.GitRepo.SetDefaultBranch(branch); err != nil {
|
|
|
|
if !git.IsErrUnsupportedVersion(err) {
|
2018-01-10 14:34:17 -07:00
|
|
|
ctx.ServerError("SetDefaultBranch", err)
|
2017-09-14 02:16:22 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := repo.UpdateDefaultBranch(); err != nil {
|
2018-01-10 14:34:17 -07:00
|
|
|
ctx.ServerError("SetDefaultBranch", err)
|
2017-09-14 02:16:22 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
|
2021-11-16 11:18:25 -07:00
|
|
|
ctx.Redirect(setting.AppSubURL + ctx.Req.URL.EscapedPath())
|
2017-09-14 02:16:22 -06:00
|
|
|
default:
|
2018-01-10 14:34:17 -07:00
|
|
|
ctx.NotFound("", nil)
|
2017-09-14 02:16:22 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SettingsProtectedBranch renders the protected branch setting page
|
|
|
|
func SettingsProtectedBranch(c *context.Context) {
|
|
|
|
branch := c.Params("*")
|
|
|
|
if !c.Repo.GitRepo.IsBranchExist(branch) {
|
2018-01-10 14:34:17 -07:00
|
|
|
c.NotFound("IsBranchExist", nil)
|
2017-09-14 02:16:22 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-03-21 12:12:49 -06:00
|
|
|
c.Data["Title"] = c.Tr("repo.settings.protected_branch") + " - " + branch
|
2017-09-14 02:16:22 -06:00
|
|
|
c.Data["PageIsSettingsBranches"] = true
|
|
|
|
|
|
|
|
protectBranch, err := models.GetProtectedBranchBy(c.Repo.Repository.ID, branch)
|
|
|
|
if err != nil {
|
2019-04-19 06:17:27 -06:00
|
|
|
if !git.IsErrBranchNotExist(err) {
|
2018-01-10 14:34:17 -07:00
|
|
|
c.ServerError("GetProtectBranchOfRepoByName", err)
|
2017-09-14 02:16:22 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if protectBranch == nil {
|
|
|
|
// No options found, create defaults.
|
|
|
|
protectBranch = &models.ProtectedBranch{
|
|
|
|
BranchName: branch,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-08 13:18:17 -06:00
|
|
|
users, err := c.Repo.Repository.GetReaders()
|
2017-09-14 02:16:22 -06:00
|
|
|
if err != nil {
|
2019-10-08 13:18:17 -06:00
|
|
|
c.ServerError("Repo.Repository.GetReaders", err)
|
2017-09-14 02:16:22 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
c.Data["Users"] = users
|
|
|
|
c.Data["whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.WhitelistUserIDs), ",")
|
2018-03-25 04:01:32 -06:00
|
|
|
c.Data["merge_whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.MergeWhitelistUserIDs), ",")
|
2018-12-11 04:28:37 -07:00
|
|
|
c.Data["approvals_whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.ApprovalsWhitelistUserIDs), ",")
|
2019-09-17 23:39:45 -06:00
|
|
|
contexts, _ := models.FindRepoRecentCommitStatusContexts(c.Repo.Repository.ID, 7*24*time.Hour) // Find last week status check contexts
|
2021-04-09 01:40:34 -06:00
|
|
|
for _, ctx := range protectBranch.StatusCheckContexts {
|
2019-09-17 23:39:45 -06:00
|
|
|
var found bool
|
2021-04-09 01:40:34 -06:00
|
|
|
for i := range contexts {
|
|
|
|
if contexts[i] == ctx {
|
2019-09-17 23:39:45 -06:00
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
2021-04-09 01:40:34 -06:00
|
|
|
contexts = append(contexts, ctx)
|
2019-09-17 23:39:45 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c.Data["branch_status_check_contexts"] = contexts
|
|
|
|
c.Data["is_context_required"] = func(context string) bool {
|
|
|
|
for _, c := range protectBranch.StatusCheckContexts {
|
|
|
|
if c == context {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2017-09-14 02:16:22 -06:00
|
|
|
|
|
|
|
if c.Repo.Owner.IsOrganization() {
|
2018-12-11 04:28:37 -07:00
|
|
|
teams, err := c.Repo.Owner.TeamsWithAccessToRepo(c.Repo.Repository.ID, models.AccessModeRead)
|
2017-09-14 02:16:22 -06:00
|
|
|
if err != nil {
|
2018-01-10 14:34:17 -07:00
|
|
|
c.ServerError("Repo.Owner.TeamsWithAccessToRepo", err)
|
2017-09-14 02:16:22 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
c.Data["Teams"] = teams
|
|
|
|
c.Data["whitelist_teams"] = strings.Join(base.Int64sToStrings(protectBranch.WhitelistTeamIDs), ",")
|
2018-03-25 04:01:32 -06:00
|
|
|
c.Data["merge_whitelist_teams"] = strings.Join(base.Int64sToStrings(protectBranch.MergeWhitelistTeamIDs), ",")
|
2018-12-11 04:28:37 -07:00
|
|
|
c.Data["approvals_whitelist_teams"] = strings.Join(base.Int64sToStrings(protectBranch.ApprovalsWhitelistTeamIDs), ",")
|
2017-09-14 02:16:22 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
c.Data["Branch"] = protectBranch
|
2021-04-05 09:30:52 -06:00
|
|
|
c.HTML(http.StatusOK, tplProtectedBranch)
|
2017-09-14 02:16:22 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// SettingsProtectedBranchPost updates the protected branch settings
|
2021-01-26 08:36:53 -07:00
|
|
|
func SettingsProtectedBranchPost(ctx *context.Context) {
|
2021-04-06 13:44:05 -06:00
|
|
|
f := web.GetForm(ctx).(*forms.ProtectBranchForm)
|
2017-09-14 02:16:22 -06:00
|
|
|
branch := ctx.Params("*")
|
|
|
|
if !ctx.Repo.GitRepo.IsBranchExist(branch) {
|
2018-01-10 14:34:17 -07:00
|
|
|
ctx.NotFound("IsBranchExist", nil)
|
2017-09-14 02:16:22 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
protectBranch, err := models.GetProtectedBranchBy(ctx.Repo.Repository.ID, branch)
|
|
|
|
if err != nil {
|
2019-04-19 06:17:27 -06:00
|
|
|
if !git.IsErrBranchNotExist(err) {
|
2018-01-10 14:34:17 -07:00
|
|
|
ctx.ServerError("GetProtectBranchOfRepoByName", err)
|
2017-09-14 02:16:22 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if f.Protected {
|
|
|
|
if protectBranch == nil {
|
|
|
|
// No options found, create defaults.
|
|
|
|
protectBranch = &models.ProtectedBranch{
|
|
|
|
RepoID: ctx.Repo.Repository.ID,
|
|
|
|
BranchName: branch,
|
|
|
|
}
|
|
|
|
}
|
2018-12-11 04:28:37 -07:00
|
|
|
if f.RequiredApprovals < 0 {
|
|
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.protected_branch_required_approvals_min"))
|
2021-11-16 11:18:25 -07:00
|
|
|
ctx.Redirect(fmt.Sprintf("%s/settings/branches/%s", ctx.Repo.RepoLink, util.PathEscapeSegments(branch)))
|
2018-12-11 04:28:37 -07:00
|
|
|
}
|
2017-09-14 02:16:22 -06:00
|
|
|
|
2018-12-11 04:28:37 -07:00
|
|
|
var whitelistUsers, whitelistTeams, mergeWhitelistUsers, mergeWhitelistTeams, approvalsWhitelistUsers, approvalsWhitelistTeams []int64
|
2019-12-03 18:08:56 -07:00
|
|
|
switch f.EnablePush {
|
|
|
|
case "all":
|
|
|
|
protectBranch.CanPush = true
|
|
|
|
protectBranch.EnableWhitelist = false
|
|
|
|
protectBranch.WhitelistDeployKeys = false
|
|
|
|
case "whitelist":
|
|
|
|
protectBranch.CanPush = true
|
|
|
|
protectBranch.EnableWhitelist = true
|
|
|
|
protectBranch.WhitelistDeployKeys = f.WhitelistDeployKeys
|
|
|
|
if strings.TrimSpace(f.WhitelistUsers) != "" {
|
|
|
|
whitelistUsers, _ = base.StringsToInt64s(strings.Split(f.WhitelistUsers, ","))
|
|
|
|
}
|
|
|
|
if strings.TrimSpace(f.WhitelistTeams) != "" {
|
|
|
|
whitelistTeams, _ = base.StringsToInt64s(strings.Split(f.WhitelistTeams, ","))
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
protectBranch.CanPush = false
|
|
|
|
protectBranch.EnableWhitelist = false
|
|
|
|
protectBranch.WhitelistDeployKeys = false
|
2018-11-28 04:26:14 -07:00
|
|
|
}
|
2019-12-03 18:08:56 -07:00
|
|
|
|
2018-03-25 04:01:32 -06:00
|
|
|
protectBranch.EnableMergeWhitelist = f.EnableMergeWhitelist
|
2019-12-03 18:08:56 -07:00
|
|
|
if f.EnableMergeWhitelist {
|
|
|
|
if strings.TrimSpace(f.MergeWhitelistUsers) != "" {
|
|
|
|
mergeWhitelistUsers, _ = base.StringsToInt64s(strings.Split(f.MergeWhitelistUsers, ","))
|
|
|
|
}
|
|
|
|
if strings.TrimSpace(f.MergeWhitelistTeams) != "" {
|
|
|
|
mergeWhitelistTeams, _ = base.StringsToInt64s(strings.Split(f.MergeWhitelistTeams, ","))
|
|
|
|
}
|
2018-11-28 04:26:14 -07:00
|
|
|
}
|
2019-09-17 23:39:45 -06:00
|
|
|
|
|
|
|
protectBranch.EnableStatusCheck = f.EnableStatusCheck
|
2019-12-03 18:08:56 -07:00
|
|
|
if f.EnableStatusCheck {
|
|
|
|
protectBranch.StatusCheckContexts = f.StatusCheckContexts
|
|
|
|
} else {
|
|
|
|
protectBranch.StatusCheckContexts = nil
|
|
|
|
}
|
2019-09-17 23:39:45 -06:00
|
|
|
|
2018-12-11 04:28:37 -07:00
|
|
|
protectBranch.RequiredApprovals = f.RequiredApprovals
|
2019-12-03 18:08:56 -07:00
|
|
|
protectBranch.EnableApprovalsWhitelist = f.EnableApprovalsWhitelist
|
|
|
|
if f.EnableApprovalsWhitelist {
|
|
|
|
if strings.TrimSpace(f.ApprovalsWhitelistUsers) != "" {
|
|
|
|
approvalsWhitelistUsers, _ = base.StringsToInt64s(strings.Split(f.ApprovalsWhitelistUsers, ","))
|
|
|
|
}
|
|
|
|
if strings.TrimSpace(f.ApprovalsWhitelistTeams) != "" {
|
|
|
|
approvalsWhitelistTeams, _ = base.StringsToInt64s(strings.Split(f.ApprovalsWhitelistTeams, ","))
|
|
|
|
}
|
2018-12-11 04:28:37 -07:00
|
|
|
}
|
2020-01-03 10:47:10 -07:00
|
|
|
protectBranch.BlockOnRejectedReviews = f.BlockOnRejectedReviews
|
2020-11-28 12:30:46 -07:00
|
|
|
protectBranch.BlockOnOfficialReviewRequests = f.BlockOnOfficialReviewRequests
|
2020-01-08 18:47:45 -07:00
|
|
|
protectBranch.DismissStaleApprovals = f.DismissStaleApprovals
|
2020-01-15 01:32:57 -07:00
|
|
|
protectBranch.RequireSignedCommits = f.RequireSignedCommits
|
2020-03-26 16:26:34 -06:00
|
|
|
protectBranch.ProtectedFilePatterns = f.ProtectedFilePatterns
|
2021-09-11 08:21:17 -06:00
|
|
|
protectBranch.UnprotectedFilePatterns = f.UnprotectedFilePatterns
|
2020-04-16 19:00:36 -06:00
|
|
|
protectBranch.BlockOnOutdatedBranch = f.BlockOnOutdatedBranch
|
2019-12-03 18:08:56 -07:00
|
|
|
|
2018-12-11 04:28:37 -07:00
|
|
|
err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, models.WhitelistOptions{
|
|
|
|
UserIDs: whitelistUsers,
|
|
|
|
TeamIDs: whitelistTeams,
|
|
|
|
MergeUserIDs: mergeWhitelistUsers,
|
|
|
|
MergeTeamIDs: mergeWhitelistTeams,
|
|
|
|
ApprovalsUserIDs: approvalsWhitelistUsers,
|
|
|
|
ApprovalsTeamIDs: approvalsWhitelistTeams,
|
|
|
|
})
|
2017-09-14 02:16:22 -06:00
|
|
|
if err != nil {
|
2018-01-10 14:34:17 -07:00
|
|
|
ctx.ServerError("UpdateProtectBranch", err)
|
2017-09-14 02:16:22 -06:00
|
|
|
return
|
|
|
|
}
|
2020-10-13 12:50:57 -06:00
|
|
|
if err = pull_service.CheckPrsForBaseBranch(ctx.Repo.Repository, protectBranch.BranchName); err != nil {
|
|
|
|
ctx.ServerError("CheckPrsForBaseBranch", err)
|
|
|
|
return
|
|
|
|
}
|
2017-09-14 02:16:22 -06:00
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.update_protect_branch_success", branch))
|
2021-11-16 11:18:25 -07:00
|
|
|
ctx.Redirect(fmt.Sprintf("%s/settings/branches/%s", ctx.Repo.RepoLink, util.PathEscapeSegments(branch)))
|
2017-09-14 02:16:22 -06:00
|
|
|
} else {
|
|
|
|
if protectBranch != nil {
|
|
|
|
if err := ctx.Repo.Repository.DeleteProtectedBranch(protectBranch.ID); err != nil {
|
2018-01-10 14:34:17 -07:00
|
|
|
ctx.ServerError("DeleteProtectedBranch", err)
|
2017-09-14 02:16:22 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.remove_protected_branch_success", branch))
|
|
|
|
ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
|
|
|
|
}
|
|
|
|
}
|
2021-10-08 11:03:04 -06:00
|
|
|
|
|
|
|
// RenameBranchPost responses for rename a branch
|
|
|
|
func RenameBranchPost(ctx *context.Context) {
|
|
|
|
form := web.GetForm(ctx).(*forms.RenameBranchForm)
|
|
|
|
|
|
|
|
if !ctx.Repo.CanCreateBranch() {
|
|
|
|
ctx.NotFound("RenameBranch", nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if ctx.HasError() {
|
|
|
|
ctx.Flash.Error(ctx.GetErrMsg())
|
|
|
|
ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
msg, err := repository.RenameBranch(ctx.Repo.Repository, ctx.User, ctx.Repo.GitRepo, form.From, form.To)
|
|
|
|
if err != nil {
|
|
|
|
ctx.ServerError("RenameBranch", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if msg == "target_exist" {
|
|
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.rename_branch_failed_exist", form.To))
|
|
|
|
ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if msg == "from_not_exist" {
|
|
|
|
ctx.Flash.Error(ctx.Tr("repo.settings.rename_branch_failed_not_exist", form.From))
|
|
|
|
ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Flash.Success(ctx.Tr("repo.settings.rename_branch_success", form.From, form.To))
|
|
|
|
ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
|
|
|
|
}
|