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.

308 lines
8.2 KiB

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