From 4d072a4c4e47140550df18edf35d7243ae5edcbd Mon Sep 17 00:00:00 2001 From: JakobDev Date: Thu, 26 Jan 2023 17:33:47 +0100 Subject: [PATCH] Add API endpoint to get latest release (#21267) This PR adds a new API endpoint to get the latest stable release of a repo, similar to [GitHub API](https://docs.github.com/en/rest/releases/releases#get-the-latest-release). --- routers/api/v1/api.go | 1 + routers/api/v1/repo/release.go | 41 ++++++++++++++++++++++++++ templates/swagger/v1_json.tmpl | 36 ++++++++++++++++++++++ tests/integration/api_releases_test.go | 18 +++++++++++ 4 files changed, 96 insertions(+) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index cd08aae414..21bc2e2de4 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1011,6 +1011,7 @@ func Routes(ctx gocontext.Context) *web.Route { m.Group("/releases", func() { m.Combo("").Get(repo.ListReleases). Post(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease) + m.Combo("/latest").Get(repo.GetLatestRelease) m.Group("/{id}", func() { m.Combo("").Get(repo.GetRelease). Patch(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease). diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index d0b20102f7..c01e66150f 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -67,6 +67,47 @@ func GetRelease(ctx *context.APIContext) { ctx.JSON(http.StatusOK, convert.ToRelease(release)) } +// GetLatestRelease gets the most recent non-prerelease, non-draft release of a repository, sorted by created_at +func GetLatestRelease(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/releases/latest repository repoGetLatestRelease + // --- + // summary: Gets the most recent non-prerelease, non-draft release of a repository, sorted by created_at + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/Release" + // "404": + // "$ref": "#/responses/notFound" + release, err := repo_model.GetLatestReleaseByRepoID(ctx.Repo.Repository.ID) + if err != nil && !repo_model.IsErrReleaseNotExist(err) { + ctx.Error(http.StatusInternalServerError, "GetLatestRelease", err) + return + } + if err != nil && repo_model.IsErrReleaseNotExist(err) || + release.IsTag || release.RepoID != ctx.Repo.Repository.ID { + ctx.NotFound() + return + } + + if err := release.LoadAttributes(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) + return + } + ctx.JSON(http.StatusOK, convert.ToRelease(release)) +} + // ListReleases list a repository's releases func ListReleases(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/releases repository repoListReleases diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 76d02d825f..cd64b7070f 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -9776,6 +9776,42 @@ } } }, + "/repos/{owner}/{repo}/releases/latest": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Gets the most recent non-prerelease, non-draft release of a repository, sorted by created_at", + "operationId": "repoGetLatestRelease", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "$ref": "#/responses/Release" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/repos/{owner}/{repo}/releases/tags/{tag}": { "get": { "produces": [ diff --git a/tests/integration/api_releases_test.go b/tests/integration/api_releases_test.go index d7f2a1b8b1..aa5816ad02 100644 --- a/tests/integration/api_releases_test.go +++ b/tests/integration/api_releases_test.go @@ -176,6 +176,24 @@ func TestAPICreateReleaseToDefaultBranchOnExistingTag(t *testing.T) { createNewReleaseUsingAPI(t, session, token, owner, repo, "v0.0.1", "", "v0.0.1", "test") } +func TestAPIGetLatestRelease(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) + + urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases/latest", + owner.Name, repo.Name) + + req := NewRequestf(t, "GET", urlStr) + resp := MakeRequest(t, req, http.StatusOK) + + var release *api.Release + DecodeJSON(t, resp, &release) + + assert.Equal(t, "testing-release", release.Title) +} + func TestAPIGetReleaseByTag(t *testing.T) { defer tests.PrepareTestEnv(t)()