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.

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