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 8.4 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
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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. }