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.

242 lines
6.6 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2018 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package repo
  6. import (
  7. "strings"
  8. "code.gitea.io/git"
  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/log"
  14. )
  15. const (
  16. tplBranch base.TplName = "repo/branch/list"
  17. )
  18. // Branch contains the branch information
  19. type Branch struct {
  20. Name string
  21. Commit *git.Commit
  22. IsProtected bool
  23. IsDeleted bool
  24. DeletedBranch *models.DeletedBranch
  25. }
  26. // Branches render repository branch page
  27. func Branches(ctx *context.Context) {
  28. ctx.Data["Title"] = "Branches"
  29. ctx.Data["IsRepoToolbarBranches"] = true
  30. ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch
  31. ctx.Data["IsWriter"] = ctx.Repo.CanWrite(models.UnitTypeCode)
  32. ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
  33. ctx.Data["PageIsViewCode"] = true
  34. ctx.Data["PageIsBranches"] = true
  35. ctx.Data["Branches"] = loadBranches(ctx)
  36. ctx.HTML(200, tplBranch)
  37. }
  38. // DeleteBranchPost responses for delete merged branch
  39. func DeleteBranchPost(ctx *context.Context) {
  40. defer redirect(ctx)
  41. branchName := ctx.Query("name")
  42. isProtected, err := ctx.Repo.Repository.IsProtectedBranch(branchName, ctx.User)
  43. if err != nil {
  44. log.Error(4, "DeleteBranch: %v", err)
  45. ctx.Flash.Error(ctx.Tr("repo.branch.deletion_failed", branchName))
  46. return
  47. }
  48. if isProtected {
  49. ctx.Flash.Error(ctx.Tr("repo.branch.protected_deletion_failed", branchName))
  50. return
  51. }
  52. if !ctx.Repo.GitRepo.IsBranchExist(branchName) || branchName == ctx.Repo.Repository.DefaultBranch {
  53. ctx.Flash.Error(ctx.Tr("repo.branch.deletion_failed", branchName))
  54. return
  55. }
  56. if err := deleteBranch(ctx, branchName); err != nil {
  57. ctx.Flash.Error(ctx.Tr("repo.branch.deletion_failed", branchName))
  58. return
  59. }
  60. ctx.Flash.Success(ctx.Tr("repo.branch.deletion_success", branchName))
  61. }
  62. // RestoreBranchPost responses for delete merged branch
  63. func RestoreBranchPost(ctx *context.Context) {
  64. defer redirect(ctx)
  65. branchID := ctx.QueryInt64("branch_id")
  66. branchName := ctx.Query("name")
  67. deletedBranch, err := ctx.Repo.Repository.GetDeletedBranchByID(branchID)
  68. if err != nil {
  69. log.Error(4, "GetDeletedBranchByID: %v", err)
  70. ctx.Flash.Error(ctx.Tr("repo.branch.restore_failed", branchName))
  71. return
  72. }
  73. if err := ctx.Repo.GitRepo.CreateBranch(deletedBranch.Name, deletedBranch.Commit); err != nil {
  74. if strings.Contains(err.Error(), "already exists") {
  75. ctx.Flash.Error(ctx.Tr("repo.branch.already_exists", deletedBranch.Name))
  76. return
  77. }
  78. log.Error(4, "CreateBranch: %v", err)
  79. ctx.Flash.Error(ctx.Tr("repo.branch.restore_failed", deletedBranch.Name))
  80. return
  81. }
  82. if err := ctx.Repo.Repository.RemoveDeletedBranch(deletedBranch.ID); err != nil {
  83. log.Error(4, "RemoveDeletedBranch: %v", err)
  84. ctx.Flash.Error(ctx.Tr("repo.branch.restore_failed", deletedBranch.Name))
  85. return
  86. }
  87. ctx.Flash.Success(ctx.Tr("repo.branch.restore_success", deletedBranch.Name))
  88. }
  89. func redirect(ctx *context.Context) {
  90. ctx.JSON(200, map[string]interface{}{
  91. "redirect": ctx.Repo.RepoLink + "/branches",
  92. })
  93. }
  94. func deleteBranch(ctx *context.Context, branchName string) error {
  95. commit, err := ctx.Repo.GitRepo.GetBranchCommit(branchName)
  96. if err != nil {
  97. log.Error(4, "GetBranchCommit: %v", err)
  98. return err
  99. }
  100. if err := ctx.Repo.GitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{
  101. Force: true,
  102. }); err != nil {
  103. log.Error(4, "DeleteBranch: %v", err)
  104. return err
  105. }
  106. // Don't return error here
  107. if err := ctx.Repo.Repository.AddDeletedBranch(branchName, commit.ID.String(), ctx.User.ID); err != nil {
  108. log.Warn("AddDeletedBranch: %v", err)
  109. }
  110. return nil
  111. }
  112. func loadBranches(ctx *context.Context) []*Branch {
  113. rawBranches, err := ctx.Repo.Repository.GetBranches()
  114. if err != nil {
  115. ctx.ServerError("GetBranches", err)
  116. return nil
  117. }
  118. branches := make([]*Branch, len(rawBranches))
  119. for i := range rawBranches {
  120. commit, err := rawBranches[i].GetCommit()
  121. if err != nil {
  122. ctx.ServerError("GetCommit", err)
  123. return nil
  124. }
  125. isProtected, err := ctx.Repo.Repository.IsProtectedBranch(rawBranches[i].Name, ctx.User)
  126. if err != nil {
  127. ctx.ServerError("IsProtectedBranch", err)
  128. return nil
  129. }
  130. branches[i] = &Branch{
  131. Name: rawBranches[i].Name,
  132. Commit: commit,
  133. IsProtected: isProtected,
  134. }
  135. }
  136. if ctx.Repo.CanWrite(models.UnitTypeCode) {
  137. deletedBranches, err := getDeletedBranches(ctx)
  138. if err != nil {
  139. ctx.ServerError("getDeletedBranches", err)
  140. return nil
  141. }
  142. branches = append(branches, deletedBranches...)
  143. }
  144. return branches
  145. }
  146. func getDeletedBranches(ctx *context.Context) ([]*Branch, error) {
  147. branches := []*Branch{}
  148. deletedBranches, err := ctx.Repo.Repository.GetDeletedBranches()
  149. if err != nil {
  150. return branches, err
  151. }
  152. for i := range deletedBranches {
  153. deletedBranches[i].LoadUser()
  154. branches = append(branches, &Branch{
  155. Name: deletedBranches[i].Name,
  156. IsDeleted: true,
  157. DeletedBranch: deletedBranches[i],
  158. })
  159. }
  160. return branches, nil
  161. }
  162. // CreateBranch creates new branch in repository
  163. func CreateBranch(ctx *context.Context, form auth.NewBranchForm) {
  164. if !ctx.Repo.CanCreateBranch() {
  165. ctx.NotFound("CreateBranch", nil)
  166. return
  167. }
  168. if ctx.HasError() {
  169. ctx.Flash.Error(ctx.GetErrMsg())
  170. ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
  171. return
  172. }
  173. var err error
  174. if ctx.Repo.IsViewBranch {
  175. err = ctx.Repo.Repository.CreateNewBranch(ctx.User, ctx.Repo.BranchName, form.NewBranchName)
  176. } else {
  177. err = ctx.Repo.Repository.CreateNewBranchFromCommit(ctx.User, ctx.Repo.BranchName, form.NewBranchName)
  178. }
  179. if err != nil {
  180. if models.IsErrTagAlreadyExists(err) {
  181. e := err.(models.ErrTagAlreadyExists)
  182. ctx.Flash.Error(ctx.Tr("repo.branch.tag_collision", e.TagName))
  183. ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
  184. return
  185. }
  186. if models.IsErrBranchAlreadyExists(err) {
  187. e := err.(models.ErrBranchAlreadyExists)
  188. ctx.Flash.Error(ctx.Tr("repo.branch.branch_already_exists", e.BranchName))
  189. ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
  190. return
  191. }
  192. if models.IsErrBranchNameConflict(err) {
  193. e := err.(models.ErrBranchNameConflict)
  194. ctx.Flash.Error(ctx.Tr("repo.branch.branch_name_conflict", form.NewBranchName, e.BranchName))
  195. ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL())
  196. return
  197. }
  198. ctx.ServerError("CreateNewBranch", err)
  199. return
  200. }
  201. ctx.Flash.Success(ctx.Tr("repo.branch.create_success", form.NewBranchName))
  202. ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + form.NewBranchName)
  203. }