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.

release.go 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. // Copyright 2016 The Gitea 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. "net/http"
  7. "code.gitea.io/gitea/models"
  8. "code.gitea.io/gitea/modules/context"
  9. "code.gitea.io/gitea/modules/convert"
  10. api "code.gitea.io/gitea/modules/structs"
  11. "code.gitea.io/gitea/routers/api/v1/utils"
  12. releaseservice "code.gitea.io/gitea/services/release"
  13. )
  14. // GetRelease get a single release of a repository
  15. func GetRelease(ctx *context.APIContext) {
  16. // swagger:operation GET /repos/{owner}/{repo}/releases/{id} repository repoGetRelease
  17. // ---
  18. // summary: Get a release
  19. // produces:
  20. // - application/json
  21. // parameters:
  22. // - name: owner
  23. // in: path
  24. // description: owner of the repo
  25. // type: string
  26. // required: true
  27. // - name: repo
  28. // in: path
  29. // description: name of the repo
  30. // type: string
  31. // required: true
  32. // - name: id
  33. // in: path
  34. // description: id of the release to get
  35. // type: integer
  36. // format: int64
  37. // required: true
  38. // responses:
  39. // "200":
  40. // "$ref": "#/responses/Release"
  41. // "404":
  42. // "$ref": "#/responses/notFound"
  43. id := ctx.ParamsInt64(":id")
  44. release, err := models.GetReleaseByID(id)
  45. if err != nil && !models.IsErrReleaseNotExist(err) {
  46. ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
  47. return
  48. }
  49. if err != nil && models.IsErrReleaseNotExist(err) ||
  50. release.IsTag || release.RepoID != ctx.Repo.Repository.ID {
  51. ctx.NotFound()
  52. return
  53. }
  54. if err := release.LoadAttributes(); err != nil {
  55. ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
  56. return
  57. }
  58. ctx.JSON(http.StatusOK, convert.ToRelease(release))
  59. }
  60. // ListReleases list a repository's releases
  61. func ListReleases(ctx *context.APIContext) {
  62. // swagger:operation GET /repos/{owner}/{repo}/releases repository repoListReleases
  63. // ---
  64. // summary: List a repo's releases
  65. // produces:
  66. // - application/json
  67. // parameters:
  68. // - name: owner
  69. // in: path
  70. // description: owner of the repo
  71. // type: string
  72. // required: true
  73. // - name: repo
  74. // in: path
  75. // description: name of the repo
  76. // type: string
  77. // required: true
  78. // - name: per_page
  79. // in: query
  80. // description: page size of results, deprecated - use limit
  81. // type: integer
  82. // deprecated: true
  83. // - name: page
  84. // in: query
  85. // description: page number of results to return (1-based)
  86. // type: integer
  87. // - name: limit
  88. // in: query
  89. // description: page size of results
  90. // type: integer
  91. // responses:
  92. // "200":
  93. // "$ref": "#/responses/ReleaseList"
  94. listOptions := utils.GetListOptions(ctx)
  95. if ctx.QueryInt("per_page") != 0 {
  96. listOptions.PageSize = ctx.QueryInt("per_page")
  97. }
  98. releases, err := models.GetReleasesByRepoID(ctx.Repo.Repository.ID, models.FindReleasesOptions{
  99. ListOptions: listOptions,
  100. IncludeDrafts: ctx.Repo.AccessMode >= models.AccessModeWrite,
  101. IncludeTags: false,
  102. })
  103. if err != nil {
  104. ctx.Error(http.StatusInternalServerError, "GetReleasesByRepoID", err)
  105. return
  106. }
  107. rels := make([]*api.Release, len(releases))
  108. for i, release := range releases {
  109. if err := release.LoadAttributes(); err != nil {
  110. ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
  111. return
  112. }
  113. rels[i] = convert.ToRelease(release)
  114. }
  115. ctx.JSON(http.StatusOK, rels)
  116. }
  117. // CreateRelease create a release
  118. func CreateRelease(ctx *context.APIContext, form api.CreateReleaseOption) {
  119. // swagger:operation POST /repos/{owner}/{repo}/releases repository repoCreateRelease
  120. // ---
  121. // summary: Create a release
  122. // consumes:
  123. // - application/json
  124. // produces:
  125. // - application/json
  126. // parameters:
  127. // - name: owner
  128. // in: path
  129. // description: owner of the repo
  130. // type: string
  131. // required: true
  132. // - name: repo
  133. // in: path
  134. // description: name of the repo
  135. // type: string
  136. // required: true
  137. // - name: body
  138. // in: body
  139. // schema:
  140. // "$ref": "#/definitions/CreateReleaseOption"
  141. // responses:
  142. // "201":
  143. // "$ref": "#/responses/Release"
  144. // "404":
  145. // "$ref": "#/responses/notFound"
  146. // "409":
  147. // "$ref": "#/responses/error"
  148. rel, err := models.GetRelease(ctx.Repo.Repository.ID, form.TagName)
  149. if err != nil {
  150. if !models.IsErrReleaseNotExist(err) {
  151. ctx.Error(http.StatusInternalServerError, "GetRelease", err)
  152. return
  153. }
  154. // If target is not provided use default branch
  155. if len(form.Target) == 0 {
  156. form.Target = ctx.Repo.Repository.DefaultBranch
  157. }
  158. rel = &models.Release{
  159. RepoID: ctx.Repo.Repository.ID,
  160. PublisherID: ctx.User.ID,
  161. Publisher: ctx.User,
  162. TagName: form.TagName,
  163. Target: form.Target,
  164. Title: form.Title,
  165. Note: form.Note,
  166. IsDraft: form.IsDraft,
  167. IsPrerelease: form.IsPrerelease,
  168. IsTag: false,
  169. Repo: ctx.Repo.Repository,
  170. }
  171. if err := releaseservice.CreateRelease(ctx.Repo.GitRepo, rel, nil); err != nil {
  172. if models.IsErrReleaseAlreadyExist(err) {
  173. ctx.Error(http.StatusConflict, "ReleaseAlreadyExist", err)
  174. } else {
  175. ctx.Error(http.StatusInternalServerError, "CreateRelease", err)
  176. }
  177. return
  178. }
  179. } else {
  180. if !rel.IsTag {
  181. ctx.Error(http.StatusConflict, "GetRelease", "Release is has no Tag")
  182. return
  183. }
  184. rel.Title = form.Title
  185. rel.Note = form.Note
  186. rel.IsDraft = form.IsDraft
  187. rel.IsPrerelease = form.IsPrerelease
  188. rel.PublisherID = ctx.User.ID
  189. rel.IsTag = false
  190. rel.Repo = ctx.Repo.Repository
  191. rel.Publisher = ctx.User
  192. if err = releaseservice.UpdateReleaseOrCreatReleaseFromTag(ctx.User, ctx.Repo.GitRepo, rel, nil, true); err != nil {
  193. ctx.Error(http.StatusInternalServerError, "UpdateReleaseOrCreatReleaseFromTag", err)
  194. return
  195. }
  196. }
  197. ctx.JSON(http.StatusCreated, convert.ToRelease(rel))
  198. }
  199. // EditRelease edit a release
  200. func EditRelease(ctx *context.APIContext, form api.EditReleaseOption) {
  201. // swagger:operation PATCH /repos/{owner}/{repo}/releases/{id} repository repoEditRelease
  202. // ---
  203. // summary: Update a release
  204. // consumes:
  205. // - application/json
  206. // produces:
  207. // - application/json
  208. // parameters:
  209. // - name: owner
  210. // in: path
  211. // description: owner of the repo
  212. // type: string
  213. // required: true
  214. // - name: repo
  215. // in: path
  216. // description: name of the repo
  217. // type: string
  218. // required: true
  219. // - name: id
  220. // in: path
  221. // description: id of the release to edit
  222. // type: integer
  223. // format: int64
  224. // required: true
  225. // - name: body
  226. // in: body
  227. // schema:
  228. // "$ref": "#/definitions/EditReleaseOption"
  229. // responses:
  230. // "200":
  231. // "$ref": "#/responses/Release"
  232. // "404":
  233. // "$ref": "#/responses/notFound"
  234. id := ctx.ParamsInt64(":id")
  235. rel, err := models.GetReleaseByID(id)
  236. if err != nil && !models.IsErrReleaseNotExist(err) {
  237. ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
  238. return
  239. }
  240. if err != nil && models.IsErrReleaseNotExist(err) ||
  241. rel.IsTag || rel.RepoID != ctx.Repo.Repository.ID {
  242. ctx.NotFound()
  243. return
  244. }
  245. if len(form.TagName) > 0 {
  246. rel.TagName = form.TagName
  247. }
  248. if len(form.Target) > 0 {
  249. rel.Target = form.Target
  250. }
  251. if len(form.Title) > 0 {
  252. rel.Title = form.Title
  253. }
  254. if len(form.Note) > 0 {
  255. rel.Note = form.Note
  256. }
  257. if form.IsDraft != nil {
  258. rel.IsDraft = *form.IsDraft
  259. }
  260. if form.IsPrerelease != nil {
  261. rel.IsPrerelease = *form.IsPrerelease
  262. }
  263. if err := releaseservice.UpdateReleaseOrCreatReleaseFromTag(ctx.User, ctx.Repo.GitRepo, rel, nil, false); err != nil {
  264. ctx.Error(http.StatusInternalServerError, "UpdateReleaseOrCreatReleaseFromTag", err)
  265. return
  266. }
  267. rel, err = models.GetReleaseByID(id)
  268. if err != nil {
  269. ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
  270. return
  271. }
  272. if err := rel.LoadAttributes(); err != nil {
  273. ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
  274. return
  275. }
  276. ctx.JSON(http.StatusOK, convert.ToRelease(rel))
  277. }
  278. // DeleteRelease delete a release from a repository
  279. func DeleteRelease(ctx *context.APIContext) {
  280. // swagger:operation DELETE /repos/{owner}/{repo}/releases/{id} repository repoDeleteRelease
  281. // ---
  282. // summary: Delete a release
  283. // parameters:
  284. // - name: owner
  285. // in: path
  286. // description: owner of the repo
  287. // type: string
  288. // required: true
  289. // - name: repo
  290. // in: path
  291. // description: name of the repo
  292. // type: string
  293. // required: true
  294. // - name: id
  295. // in: path
  296. // description: id of the release to delete
  297. // type: integer
  298. // format: int64
  299. // required: true
  300. // responses:
  301. // "204":
  302. // "$ref": "#/responses/empty"
  303. // "404":
  304. // "$ref": "#/responses/notFound"
  305. id := ctx.ParamsInt64(":id")
  306. rel, err := models.GetReleaseByID(id)
  307. if err != nil && !models.IsErrReleaseNotExist(err) {
  308. ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
  309. return
  310. }
  311. if err != nil && models.IsErrReleaseNotExist(err) ||
  312. rel.IsTag || rel.RepoID != ctx.Repo.Repository.ID {
  313. ctx.NotFound()
  314. return
  315. }
  316. if err := releaseservice.DeleteReleaseByID(id, ctx.User, false); err != nil {
  317. ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err)
  318. return
  319. }
  320. ctx.Status(http.StatusNoContent)
  321. }