summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakobDev <jakobdev@gmx.de>2023-01-26 17:33:47 +0100
committerGitHub <noreply@github.com>2023-01-26 10:33:47 -0600
commit4d072a4c4e47140550df18edf35d7243ae5edcbd (patch)
treec1bb19442518481494895f6b37cc6604bf8788e8
parente8ac6a9aeacf0adf21982abc51baa8938e5dd6bb (diff)
downloadgitea-4d072a4c4e47140550df18edf35d7243ae5edcbd.tar.gz
gitea-4d072a4c4e47140550df18edf35d7243ae5edcbd.zip
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).
-rw-r--r--routers/api/v1/api.go1
-rw-r--r--routers/api/v1/repo/release.go41
-rw-r--r--templates/swagger/v1_json.tmpl36
-rw-r--r--tests/integration/api_releases_test.go18
4 files changed, 96 insertions, 0 deletions
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)()