You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

setting_protected_branch.go 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package repo
  5. import (
  6. "fmt"
  7. "strings"
  8. "time"
  9. "code.gitea.io/gitea/models"
  10. "code.gitea.io/gitea/modules/auth"
  11. "code.gitea.io/gitea/modules/base"
  12. "code.gitea.io/gitea/modules/context"
  13. "code.gitea.io/gitea/modules/git"
  14. "code.gitea.io/gitea/modules/log"
  15. "code.gitea.io/gitea/modules/setting"
  16. )
  17. // ProtectedBranch render the page to protect the repository
  18. func ProtectedBranch(ctx *context.Context) {
  19. ctx.Data["Title"] = ctx.Tr("repo.settings")
  20. ctx.Data["PageIsSettingsBranches"] = true
  21. protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches()
  22. if err != nil {
  23. ctx.ServerError("GetProtectedBranches", err)
  24. return
  25. }
  26. ctx.Data["ProtectedBranches"] = protectedBranches
  27. branches := ctx.Data["Branches"].([]string)
  28. leftBranches := make([]string, 0, len(branches)-len(protectedBranches))
  29. for _, b := range branches {
  30. var protected bool
  31. for _, pb := range protectedBranches {
  32. if b == pb.BranchName {
  33. protected = true
  34. break
  35. }
  36. }
  37. if !protected {
  38. leftBranches = append(leftBranches, b)
  39. }
  40. }
  41. ctx.Data["LeftBranches"] = leftBranches
  42. ctx.HTML(200, tplBranches)
  43. }
  44. // ProtectedBranchPost response for protect for a branch of a repository
  45. func ProtectedBranchPost(ctx *context.Context) {
  46. ctx.Data["Title"] = ctx.Tr("repo.settings")
  47. ctx.Data["PageIsSettingsBranches"] = true
  48. repo := ctx.Repo.Repository
  49. switch ctx.Query("action") {
  50. case "default_branch":
  51. if ctx.HasError() {
  52. ctx.HTML(200, tplBranches)
  53. return
  54. }
  55. branch := ctx.Query("branch")
  56. if !ctx.Repo.GitRepo.IsBranchExist(branch) {
  57. ctx.Status(404)
  58. return
  59. } else if repo.DefaultBranch != branch {
  60. repo.DefaultBranch = branch
  61. if err := ctx.Repo.GitRepo.SetDefaultBranch(branch); err != nil {
  62. if !git.IsErrUnsupportedVersion(err) {
  63. ctx.ServerError("SetDefaultBranch", err)
  64. return
  65. }
  66. }
  67. if err := repo.UpdateDefaultBranch(); err != nil {
  68. ctx.ServerError("SetDefaultBranch", err)
  69. return
  70. }
  71. }
  72. log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
  73. ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))
  74. ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path)
  75. default:
  76. ctx.NotFound("", nil)
  77. }
  78. }
  79. // SettingsProtectedBranch renders the protected branch setting page
  80. func SettingsProtectedBranch(c *context.Context) {
  81. branch := c.Params("*")
  82. if !c.Repo.GitRepo.IsBranchExist(branch) {
  83. c.NotFound("IsBranchExist", nil)
  84. return
  85. }
  86. c.Data["Title"] = c.Tr("repo.settings.protected_branch") + " - " + branch
  87. c.Data["PageIsSettingsBranches"] = true
  88. protectBranch, err := models.GetProtectedBranchBy(c.Repo.Repository.ID, branch)
  89. if err != nil {
  90. if !git.IsErrBranchNotExist(err) {
  91. c.ServerError("GetProtectBranchOfRepoByName", err)
  92. return
  93. }
  94. }
  95. if protectBranch == nil {
  96. // No options found, create defaults.
  97. protectBranch = &models.ProtectedBranch{
  98. BranchName: branch,
  99. }
  100. }
  101. users, err := c.Repo.Repository.GetReaders()
  102. if err != nil {
  103. c.ServerError("Repo.Repository.GetReaders", err)
  104. return
  105. }
  106. c.Data["Users"] = users
  107. c.Data["whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.WhitelistUserIDs), ",")
  108. c.Data["merge_whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.MergeWhitelistUserIDs), ",")
  109. c.Data["approvals_whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.ApprovalsWhitelistUserIDs), ",")
  110. contexts, _ := models.FindRepoRecentCommitStatusContexts(c.Repo.Repository.ID, 7*24*time.Hour) // Find last week status check contexts
  111. for _, context := range protectBranch.StatusCheckContexts {
  112. var found bool
  113. for _, ctx := range contexts {
  114. if ctx == context {
  115. found = true
  116. break
  117. }
  118. }
  119. if !found {
  120. contexts = append(contexts, context)
  121. }
  122. }
  123. c.Data["branch_status_check_contexts"] = contexts
  124. c.Data["is_context_required"] = func(context string) bool {
  125. for _, c := range protectBranch.StatusCheckContexts {
  126. if c == context {
  127. return true
  128. }
  129. }
  130. return false
  131. }
  132. if c.Repo.Owner.IsOrganization() {
  133. teams, err := c.Repo.Owner.TeamsWithAccessToRepo(c.Repo.Repository.ID, models.AccessModeRead)
  134. if err != nil {
  135. c.ServerError("Repo.Owner.TeamsWithAccessToRepo", err)
  136. return
  137. }
  138. c.Data["Teams"] = teams
  139. c.Data["whitelist_teams"] = strings.Join(base.Int64sToStrings(protectBranch.WhitelistTeamIDs), ",")
  140. c.Data["merge_whitelist_teams"] = strings.Join(base.Int64sToStrings(protectBranch.MergeWhitelistTeamIDs), ",")
  141. c.Data["approvals_whitelist_teams"] = strings.Join(base.Int64sToStrings(protectBranch.ApprovalsWhitelistTeamIDs), ",")
  142. }
  143. c.Data["Branch"] = protectBranch
  144. c.HTML(200, tplProtectedBranch)
  145. }
  146. // SettingsProtectedBranchPost updates the protected branch settings
  147. func SettingsProtectedBranchPost(ctx *context.Context, f auth.ProtectBranchForm) {
  148. branch := ctx.Params("*")
  149. if !ctx.Repo.GitRepo.IsBranchExist(branch) {
  150. ctx.NotFound("IsBranchExist", nil)
  151. return
  152. }
  153. protectBranch, err := models.GetProtectedBranchBy(ctx.Repo.Repository.ID, branch)
  154. if err != nil {
  155. if !git.IsErrBranchNotExist(err) {
  156. ctx.ServerError("GetProtectBranchOfRepoByName", err)
  157. return
  158. }
  159. }
  160. if f.Protected {
  161. if protectBranch == nil {
  162. // No options found, create defaults.
  163. protectBranch = &models.ProtectedBranch{
  164. RepoID: ctx.Repo.Repository.ID,
  165. BranchName: branch,
  166. }
  167. }
  168. if f.RequiredApprovals < 0 {
  169. ctx.Flash.Error(ctx.Tr("repo.settings.protected_branch_required_approvals_min"))
  170. ctx.Redirect(fmt.Sprintf("%s/settings/branches/%s", ctx.Repo.RepoLink, branch))
  171. }
  172. var whitelistUsers, whitelistTeams, mergeWhitelistUsers, mergeWhitelistTeams, approvalsWhitelistUsers, approvalsWhitelistTeams []int64
  173. switch f.EnablePush {
  174. case "all":
  175. protectBranch.CanPush = true
  176. protectBranch.EnableWhitelist = false
  177. protectBranch.WhitelistDeployKeys = false
  178. case "whitelist":
  179. protectBranch.CanPush = true
  180. protectBranch.EnableWhitelist = true
  181. protectBranch.WhitelistDeployKeys = f.WhitelistDeployKeys
  182. if strings.TrimSpace(f.WhitelistUsers) != "" {
  183. whitelistUsers, _ = base.StringsToInt64s(strings.Split(f.WhitelistUsers, ","))
  184. }
  185. if strings.TrimSpace(f.WhitelistTeams) != "" {
  186. whitelistTeams, _ = base.StringsToInt64s(strings.Split(f.WhitelistTeams, ","))
  187. }
  188. default:
  189. protectBranch.CanPush = false
  190. protectBranch.EnableWhitelist = false
  191. protectBranch.WhitelistDeployKeys = false
  192. }
  193. protectBranch.EnableMergeWhitelist = f.EnableMergeWhitelist
  194. if f.EnableMergeWhitelist {
  195. if strings.TrimSpace(f.MergeWhitelistUsers) != "" {
  196. mergeWhitelistUsers, _ = base.StringsToInt64s(strings.Split(f.MergeWhitelistUsers, ","))
  197. }
  198. if strings.TrimSpace(f.MergeWhitelistTeams) != "" {
  199. mergeWhitelistTeams, _ = base.StringsToInt64s(strings.Split(f.MergeWhitelistTeams, ","))
  200. }
  201. }
  202. protectBranch.EnableStatusCheck = f.EnableStatusCheck
  203. if f.EnableStatusCheck {
  204. protectBranch.StatusCheckContexts = f.StatusCheckContexts
  205. } else {
  206. protectBranch.StatusCheckContexts = nil
  207. }
  208. protectBranch.RequiredApprovals = f.RequiredApprovals
  209. protectBranch.EnableApprovalsWhitelist = f.EnableApprovalsWhitelist
  210. if f.EnableApprovalsWhitelist {
  211. if strings.TrimSpace(f.ApprovalsWhitelistUsers) != "" {
  212. approvalsWhitelistUsers, _ = base.StringsToInt64s(strings.Split(f.ApprovalsWhitelistUsers, ","))
  213. }
  214. if strings.TrimSpace(f.ApprovalsWhitelistTeams) != "" {
  215. approvalsWhitelistTeams, _ = base.StringsToInt64s(strings.Split(f.ApprovalsWhitelistTeams, ","))
  216. }
  217. }
  218. err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, models.WhitelistOptions{
  219. UserIDs: whitelistUsers,
  220. TeamIDs: whitelistTeams,
  221. MergeUserIDs: mergeWhitelistUsers,
  222. MergeTeamIDs: mergeWhitelistTeams,
  223. ApprovalsUserIDs: approvalsWhitelistUsers,
  224. ApprovalsTeamIDs: approvalsWhitelistTeams,
  225. })
  226. if err != nil {
  227. ctx.ServerError("UpdateProtectBranch", err)
  228. return
  229. }
  230. ctx.Flash.Success(ctx.Tr("repo.settings.update_protect_branch_success", branch))
  231. ctx.Redirect(fmt.Sprintf("%s/settings/branches/%s", ctx.Repo.RepoLink, branch))
  232. } else {
  233. if protectBranch != nil {
  234. if err := ctx.Repo.Repository.DeleteProtectedBranch(protectBranch.ID); err != nil {
  235. ctx.ServerError("DeleteProtectedBranch", err)
  236. return
  237. }
  238. }
  239. ctx.Flash.Success(ctx.Tr("repo.settings.remove_protected_branch_success", branch))
  240. ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink))
  241. }
  242. }