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

release.go 7.9 kB

11 years ago
11 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
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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. "fmt"
  7. "code.gitea.io/gitea/models"
  8. "code.gitea.io/gitea/modules/auth"
  9. "code.gitea.io/gitea/modules/base"
  10. "code.gitea.io/gitea/modules/context"
  11. "code.gitea.io/gitea/modules/log"
  12. "code.gitea.io/gitea/modules/markdown"
  13. "code.gitea.io/gitea/modules/setting"
  14. "github.com/Unknwon/paginater"
  15. )
  16. const (
  17. tplReleases base.TplName = "repo/release/list"
  18. tplReleaseNew base.TplName = "repo/release/new"
  19. )
  20. // calReleaseNumCommitsBehind calculates given release has how many commits behind release target.
  21. func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *models.Release, countCache map[string]int64) error {
  22. // Fast return if release target is same as default branch.
  23. if repoCtx.BranchName == release.Target {
  24. release.NumCommitsBehind = repoCtx.CommitsCount - release.NumCommits
  25. return nil
  26. }
  27. // Get count if not exists
  28. if _, ok := countCache[release.Target]; !ok {
  29. if repoCtx.GitRepo.IsBranchExist(release.Target) {
  30. commit, err := repoCtx.GitRepo.GetBranchCommit(release.Target)
  31. if err != nil {
  32. return fmt.Errorf("GetBranchCommit: %v", err)
  33. }
  34. countCache[release.Target], err = commit.CommitsCount()
  35. if err != nil {
  36. return fmt.Errorf("CommitsCount: %v", err)
  37. }
  38. } else {
  39. // Use NumCommits of the newest release on that target
  40. countCache[release.Target] = release.NumCommits
  41. }
  42. }
  43. release.NumCommitsBehind = countCache[release.Target] - release.NumCommits
  44. return nil
  45. }
  46. // Releases render releases list page
  47. func Releases(ctx *context.Context) {
  48. ctx.Data["Title"] = ctx.Tr("repo.release.releases")
  49. ctx.Data["PageIsReleaseList"] = true
  50. page := ctx.QueryInt("page")
  51. if page <= 1 {
  52. page = 1
  53. }
  54. limit := ctx.QueryInt("limit")
  55. if limit <= 0 {
  56. limit = 10
  57. }
  58. releases, err := models.GetReleasesByRepoID(ctx.Repo.Repository.ID, page, limit)
  59. if err != nil {
  60. ctx.Handle(500, "GetReleasesByRepoIDAndNames", err)
  61. return
  62. }
  63. err = models.GetReleaseAttachments(releases...)
  64. if err != nil {
  65. ctx.Handle(500, "GetReleaseAttachments", err)
  66. return
  67. }
  68. // Temporary cache commits count of used branches to speed up.
  69. countCache := make(map[string]int64)
  70. cacheUsers := map[int64]*models.User{ctx.User.ID: ctx.User}
  71. var ok bool
  72. releasesToDisplay := make([]*models.Release, 0, len(releases))
  73. for _, r := range releases {
  74. if r.IsDraft && !ctx.Repo.IsOwner() {
  75. continue
  76. }
  77. if r.Publisher, ok = cacheUsers[r.PublisherID]; !ok {
  78. r.Publisher, err = models.GetUserByID(r.PublisherID)
  79. if err != nil {
  80. if models.IsErrUserNotExist(err) {
  81. r.Publisher = models.NewGhostUser()
  82. } else {
  83. ctx.Handle(500, "GetUserByID", err)
  84. return
  85. }
  86. }
  87. cacheUsers[r.PublisherID] = r.Publisher
  88. }
  89. if err := calReleaseNumCommitsBehind(ctx.Repo, r, countCache); err != nil {
  90. ctx.Handle(500, "calReleaseNumCommitsBehind", err)
  91. return
  92. }
  93. r.Note = markdown.RenderString(r.Note, ctx.Repo.RepoLink, ctx.Repo.Repository.ComposeMetas())
  94. releasesToDisplay = append(releasesToDisplay, r)
  95. }
  96. pager := paginater.New(len(releasesToDisplay), limit, page, 5)
  97. ctx.Data["Page"] = pager
  98. ctx.Data["Releases"] = releasesToDisplay
  99. ctx.HTML(200, tplReleases)
  100. }
  101. // NewRelease render creating release page
  102. func NewRelease(ctx *context.Context) {
  103. ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
  104. ctx.Data["PageIsReleaseList"] = true
  105. ctx.Data["tag_target"] = ctx.Repo.Repository.DefaultBranch
  106. renderAttachmentSettings(ctx)
  107. ctx.HTML(200, tplReleaseNew)
  108. }
  109. // NewReleasePost response for creating a release
  110. func NewReleasePost(ctx *context.Context, form auth.NewReleaseForm) {
  111. ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
  112. ctx.Data["PageIsReleaseList"] = true
  113. if ctx.HasError() {
  114. ctx.HTML(200, tplReleaseNew)
  115. return
  116. }
  117. if !ctx.Repo.GitRepo.IsBranchExist(form.Target) {
  118. ctx.RenderWithErr(ctx.Tr("form.target_branch_not_exist"), tplReleaseNew, &form)
  119. return
  120. }
  121. var tagCreatedUnix int64
  122. tag, err := ctx.Repo.GitRepo.GetTag(form.TagName)
  123. if err == nil {
  124. commit, err := tag.Commit()
  125. if err == nil {
  126. tagCreatedUnix = commit.Author.When.Unix()
  127. }
  128. }
  129. commit, err := ctx.Repo.GitRepo.GetBranchCommit(form.Target)
  130. if err != nil {
  131. ctx.Handle(500, "GetBranchCommit", err)
  132. return
  133. }
  134. commitsCount, err := commit.CommitsCount()
  135. if err != nil {
  136. ctx.Handle(500, "CommitsCount", err)
  137. return
  138. }
  139. rel := &models.Release{
  140. RepoID: ctx.Repo.Repository.ID,
  141. PublisherID: ctx.User.ID,
  142. Title: form.Title,
  143. TagName: form.TagName,
  144. Target: form.Target,
  145. Sha1: commit.ID.String(),
  146. NumCommits: commitsCount,
  147. Note: form.Content,
  148. IsDraft: len(form.Draft) > 0,
  149. IsPrerelease: form.Prerelease,
  150. CreatedUnix: tagCreatedUnix,
  151. }
  152. var attachmentUUIDs []string
  153. if setting.AttachmentEnabled {
  154. attachmentUUIDs = form.Files
  155. }
  156. if err = models.CreateRelease(ctx.Repo.GitRepo, rel, attachmentUUIDs); err != nil {
  157. ctx.Data["Err_TagName"] = true
  158. switch {
  159. case models.IsErrReleaseAlreadyExist(err):
  160. ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), tplReleaseNew, &form)
  161. case models.IsErrInvalidTagName(err):
  162. ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_invalid"), tplReleaseNew, &form)
  163. default:
  164. ctx.Handle(500, "CreateRelease", err)
  165. }
  166. return
  167. }
  168. log.Trace("Release created: %s/%s:%s", ctx.User.LowerName, ctx.Repo.Repository.Name, form.TagName)
  169. ctx.Redirect(ctx.Repo.RepoLink + "/releases")
  170. }
  171. // EditRelease render release edit page
  172. func EditRelease(ctx *context.Context) {
  173. ctx.Data["Title"] = ctx.Tr("repo.release.edit_release")
  174. ctx.Data["PageIsReleaseList"] = true
  175. ctx.Data["PageIsEditRelease"] = true
  176. renderAttachmentSettings(ctx)
  177. tagName := ctx.Params("*")
  178. rel, err := models.GetRelease(ctx.Repo.Repository.ID, tagName)
  179. if err != nil {
  180. if models.IsErrReleaseNotExist(err) {
  181. ctx.Handle(404, "GetRelease", err)
  182. } else {
  183. ctx.Handle(500, "GetRelease", err)
  184. }
  185. return
  186. }
  187. ctx.Data["ID"] = rel.ID
  188. ctx.Data["tag_name"] = rel.TagName
  189. ctx.Data["tag_target"] = rel.Target
  190. ctx.Data["title"] = rel.Title
  191. ctx.Data["content"] = rel.Note
  192. ctx.Data["prerelease"] = rel.IsPrerelease
  193. ctx.Data["IsDraft"] = rel.IsDraft
  194. ctx.HTML(200, tplReleaseNew)
  195. }
  196. // EditReleasePost response for edit release
  197. func EditReleasePost(ctx *context.Context, form auth.EditReleaseForm) {
  198. ctx.Data["Title"] = ctx.Tr("repo.release.edit_release")
  199. ctx.Data["PageIsReleaseList"] = true
  200. ctx.Data["PageIsEditRelease"] = true
  201. tagName := ctx.Params("*")
  202. rel, err := models.GetRelease(ctx.Repo.Repository.ID, tagName)
  203. if err != nil {
  204. if models.IsErrReleaseNotExist(err) {
  205. ctx.Handle(404, "GetRelease", err)
  206. } else {
  207. ctx.Handle(500, "GetRelease", err)
  208. }
  209. return
  210. }
  211. ctx.Data["tag_name"] = rel.TagName
  212. ctx.Data["tag_target"] = rel.Target
  213. ctx.Data["title"] = rel.Title
  214. ctx.Data["content"] = rel.Note
  215. ctx.Data["prerelease"] = rel.IsPrerelease
  216. if ctx.HasError() {
  217. ctx.HTML(200, tplReleaseNew)
  218. return
  219. }
  220. var attachmentUUIDs []string
  221. if setting.AttachmentEnabled {
  222. attachmentUUIDs = form.Files
  223. }
  224. rel.Title = form.Title
  225. rel.Note = form.Content
  226. rel.IsDraft = len(form.Draft) > 0
  227. rel.IsPrerelease = form.Prerelease
  228. if err = models.UpdateRelease(ctx.Repo.GitRepo, rel, attachmentUUIDs); err != nil {
  229. ctx.Handle(500, "UpdateRelease", err)
  230. return
  231. }
  232. ctx.Redirect(ctx.Repo.RepoLink + "/releases")
  233. }
  234. // DeleteRelease delete a release
  235. func DeleteRelease(ctx *context.Context) {
  236. delTag := ctx.QueryBool("delTag")
  237. if err := models.DeleteReleaseByID(ctx.QueryInt64("id"), ctx.User, delTag); err != nil {
  238. ctx.Flash.Error("DeleteReleaseByID: " + err.Error())
  239. } else {
  240. ctx.Flash.Success(ctx.Tr("repo.release.deletion_success"))
  241. }
  242. ctx.JSON(200, map[string]interface{}{
  243. "redirect": ctx.Repo.RepoLink + "/releases",
  244. })
  245. }