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.6KB

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