[API] ListReleases add filter for draft and pre-releases (#16175)
* invent ctx.QueryOptionalBool * [API] ListReleases add draft and pre-release filter * Add X-Total-Count header * Add a release to fixtures * Add TEST for API ListReleases
This commit is contained in:
parent
c9d053f0ca
commit
6ad5d0a306
9 changed files with 158 additions and 22 deletions
|
@ -7,6 +7,7 @@ package integrations
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
@ -16,6 +17,58 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestAPIListReleases(t *testing.T) {
|
||||||
|
defer prepareTestEnv(t)()
|
||||||
|
|
||||||
|
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
|
||||||
|
user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
|
||||||
|
session := loginUser(t, user2.LowerName)
|
||||||
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
|
||||||
|
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/releases", user2.Name, repo.Name))
|
||||||
|
link.RawQuery = url.Values{"token": {token}}.Encode()
|
||||||
|
resp := session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||||
|
var apiReleases []*api.Release
|
||||||
|
DecodeJSON(t, resp, &apiReleases)
|
||||||
|
if assert.Len(t, apiReleases, 3) {
|
||||||
|
for _, release := range apiReleases {
|
||||||
|
switch release.ID {
|
||||||
|
case 1:
|
||||||
|
assert.False(t, release.IsDraft)
|
||||||
|
assert.False(t, release.IsPrerelease)
|
||||||
|
case 4:
|
||||||
|
assert.True(t, release.IsDraft)
|
||||||
|
assert.False(t, release.IsPrerelease)
|
||||||
|
case 5:
|
||||||
|
assert.False(t, release.IsDraft)
|
||||||
|
assert.True(t, release.IsPrerelease)
|
||||||
|
default:
|
||||||
|
assert.NoError(t, fmt.Errorf("unexpected release: %v", release))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test filter
|
||||||
|
testFilterByLen := func(auth bool, query url.Values, expectedLength int, msgAndArgs ...string) {
|
||||||
|
link.RawQuery = query.Encode()
|
||||||
|
if auth {
|
||||||
|
query.Set("token", token)
|
||||||
|
resp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||||
|
} else {
|
||||||
|
resp = MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
|
||||||
|
}
|
||||||
|
DecodeJSON(t, resp, &apiReleases)
|
||||||
|
assert.Len(t, apiReleases, expectedLength, msgAndArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
testFilterByLen(false, url.Values{"draft": {"true"}}, 0, "anon should not see drafts")
|
||||||
|
testFilterByLen(true, url.Values{"draft": {"true"}}, 1, "repo owner should see drafts")
|
||||||
|
testFilterByLen(true, url.Values{"draft": {"false"}}, 2, "exclude drafts")
|
||||||
|
testFilterByLen(true, url.Values{"draft": {"false"}, "pre-release": {"false"}}, 1, "exclude drafts and pre-releases")
|
||||||
|
testFilterByLen(true, url.Values{"pre-release": {"true"}}, 1, "only get pre-release")
|
||||||
|
testFilterByLen(true, url.Values{"draft": {"true"}, "pre-release": {"true"}}, 0, "there is no pre-release draft")
|
||||||
|
}
|
||||||
|
|
||||||
func createNewReleaseUsingAPI(t *testing.T, session *TestSession, token string, owner *models.User, repo *models.Repository, name, target, title, desc string) *api.Release {
|
func createNewReleaseUsingAPI(t *testing.T, session *TestSession, token string, owner *models.User, repo *models.Repository, name, target, title, desc string) *api.Release {
|
||||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases?token=%s",
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases?token=%s",
|
||||||
owner.Name, repo.Name, token)
|
owner.Name, repo.Name, token)
|
||||||
|
|
|
@ -223,7 +223,7 @@ func TestAPIViewRepo(t *testing.T) {
|
||||||
DecodeJSON(t, resp, &repo)
|
DecodeJSON(t, resp, &repo)
|
||||||
assert.EqualValues(t, 1, repo.ID)
|
assert.EqualValues(t, 1, repo.ID)
|
||||||
assert.EqualValues(t, "repo1", repo.Name)
|
assert.EqualValues(t, "repo1", repo.Name)
|
||||||
assert.EqualValues(t, 2, repo.Releases)
|
assert.EqualValues(t, 3, repo.Releases)
|
||||||
assert.EqualValues(t, 1, repo.OpenIssues)
|
assert.EqualValues(t, 1, repo.OpenIssues)
|
||||||
assert.EqualValues(t, 3, repo.OpenPulls)
|
assert.EqualValues(t, 3, repo.OpenPulls)
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ func TestCreateRelease(t *testing.T) {
|
||||||
session := loginUser(t, "user2")
|
session := loginUser(t, "user2")
|
||||||
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, false)
|
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, false)
|
||||||
|
|
||||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.stable"), 3)
|
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.stable"), 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateReleasePreRelease(t *testing.T) {
|
func TestCreateReleasePreRelease(t *testing.T) {
|
||||||
|
@ -94,7 +94,7 @@ func TestCreateReleasePreRelease(t *testing.T) {
|
||||||
session := loginUser(t, "user2")
|
session := loginUser(t, "user2")
|
||||||
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", true, false)
|
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", true, false)
|
||||||
|
|
||||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.prerelease"), 3)
|
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.prerelease"), 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateReleaseDraft(t *testing.T) {
|
func TestCreateReleaseDraft(t *testing.T) {
|
||||||
|
@ -103,7 +103,7 @@ func TestCreateReleaseDraft(t *testing.T) {
|
||||||
session := loginUser(t, "user2")
|
session := loginUser(t, "user2")
|
||||||
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, true)
|
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, true)
|
||||||
|
|
||||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.draft"), 3)
|
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.draft"), 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateReleasePaging(t *testing.T) {
|
func TestCreateReleasePaging(t *testing.T) {
|
||||||
|
@ -142,7 +142,7 @@ func TestViewReleaseListNoLogin(t *testing.T) {
|
||||||
|
|
||||||
htmlDoc := NewHTMLParser(t, rsp.Body)
|
htmlDoc := NewHTMLParser(t, rsp.Body)
|
||||||
releases := htmlDoc.Find("#release-list li.ui.grid")
|
releases := htmlDoc.Find("#release-list li.ui.grid")
|
||||||
assert.Equal(t, 1, releases.Length())
|
assert.Equal(t, 2, releases.Length())
|
||||||
|
|
||||||
links := make([]string, 0, 5)
|
links := make([]string, 0, 5)
|
||||||
releases.Each(func(i int, s *goquery.Selection) {
|
releases.Each(func(i int, s *goquery.Selection) {
|
||||||
|
@ -153,7 +153,7 @@ func TestViewReleaseListNoLogin(t *testing.T) {
|
||||||
links = append(links, link)
|
links = append(links, link)
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.EqualValues(t, []string{"/user2/repo1/releases/tag/v1.1"}, links)
|
assert.EqualValues(t, []string{"/user2/repo1/releases/tag/v1.0", "/user2/repo1/releases/tag/v1.1"}, links)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestViewReleaseListLogin(t *testing.T) {
|
func TestViewReleaseListLogin(t *testing.T) {
|
||||||
|
@ -169,7 +169,7 @@ func TestViewReleaseListLogin(t *testing.T) {
|
||||||
|
|
||||||
htmlDoc := NewHTMLParser(t, rsp.Body)
|
htmlDoc := NewHTMLParser(t, rsp.Body)
|
||||||
releases := htmlDoc.Find("#release-list li.ui.grid")
|
releases := htmlDoc.Find("#release-list li.ui.grid")
|
||||||
assert.Equal(t, 2, releases.Length())
|
assert.Equal(t, 3, releases.Length())
|
||||||
|
|
||||||
links := make([]string, 0, 5)
|
links := make([]string, 0, 5)
|
||||||
releases.Each(func(i int, s *goquery.Selection) {
|
releases.Each(func(i int, s *goquery.Selection) {
|
||||||
|
@ -180,8 +180,11 @@ func TestViewReleaseListLogin(t *testing.T) {
|
||||||
links = append(links, link)
|
links = append(links, link)
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.EqualValues(t, []string{"/user2/repo1/releases/tag/draft-release",
|
assert.EqualValues(t, []string{
|
||||||
"/user2/repo1/releases/tag/v1.1"}, links)
|
"/user2/repo1/releases/tag/draft-release",
|
||||||
|
"/user2/repo1/releases/tag/v1.0",
|
||||||
|
"/user2/repo1/releases/tag/v1.1",
|
||||||
|
}, links)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestViewTagsList(t *testing.T) {
|
func TestViewTagsList(t *testing.T) {
|
||||||
|
@ -197,12 +200,12 @@ func TestViewTagsList(t *testing.T) {
|
||||||
|
|
||||||
htmlDoc := NewHTMLParser(t, rsp.Body)
|
htmlDoc := NewHTMLParser(t, rsp.Body)
|
||||||
tags := htmlDoc.Find(".tag-list tr")
|
tags := htmlDoc.Find(".tag-list tr")
|
||||||
assert.Equal(t, 2, tags.Length())
|
assert.Equal(t, 3, tags.Length())
|
||||||
|
|
||||||
tagNames := make([]string, 0, 5)
|
tagNames := make([]string, 0, 5)
|
||||||
tags.Each(func(i int, s *goquery.Selection) {
|
tags.Each(func(i int, s *goquery.Selection) {
|
||||||
tagNames = append(tagNames, s.Find(".tag a.df.ac").Text())
|
tagNames = append(tagNames, s.Find(".tag a.df.ac").Text())
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.EqualValues(t, []string{"delete-tag", "v1.1"}, tagNames)
|
assert.EqualValues(t, []string{"v1.0", "delete-tag", "v1.1"}, tagNames)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
-
|
- id: 1
|
||||||
id: 1
|
|
||||||
repo_id: 1
|
repo_id: 1
|
||||||
publisher_id: 2
|
publisher_id: 2
|
||||||
tag_name: "v1.1"
|
tag_name: "v1.1"
|
||||||
|
@ -13,8 +12,7 @@
|
||||||
is_tag: false
|
is_tag: false
|
||||||
created_unix: 946684800
|
created_unix: 946684800
|
||||||
|
|
||||||
-
|
- id: 2
|
||||||
id: 2
|
|
||||||
repo_id: 40
|
repo_id: 40
|
||||||
publisher_id: 2
|
publisher_id: 2
|
||||||
tag_name: "v1.1"
|
tag_name: "v1.1"
|
||||||
|
@ -28,8 +26,7 @@
|
||||||
is_tag: false
|
is_tag: false
|
||||||
created_unix: 946684800
|
created_unix: 946684800
|
||||||
|
|
||||||
-
|
- id: 3
|
||||||
id: 3
|
|
||||||
repo_id: 1
|
repo_id: 1
|
||||||
publisher_id: 2
|
publisher_id: 2
|
||||||
tag_name: "delete-tag"
|
tag_name: "delete-tag"
|
||||||
|
@ -43,8 +40,7 @@
|
||||||
is_tag: true
|
is_tag: true
|
||||||
created_unix: 946684800
|
created_unix: 946684800
|
||||||
|
|
||||||
-
|
- id: 4
|
||||||
id: 4
|
|
||||||
repo_id: 1
|
repo_id: 1
|
||||||
publisher_id: 2
|
publisher_id: 2
|
||||||
tag_name: "draft-release"
|
tag_name: "draft-release"
|
||||||
|
@ -55,3 +51,18 @@
|
||||||
is_prerelease: false
|
is_prerelease: false
|
||||||
is_tag: false
|
is_tag: false
|
||||||
created_unix: 1619524806
|
created_unix: 1619524806
|
||||||
|
|
||||||
|
- id: 5
|
||||||
|
repo_id: 1
|
||||||
|
publisher_id: 2
|
||||||
|
tag_name: "v1.0"
|
||||||
|
lower_tag_name: "v1.0"
|
||||||
|
target: "master"
|
||||||
|
title: "pre-release"
|
||||||
|
note: "some text for a pre release"
|
||||||
|
sha1: "65f1bf27bc3bf70f64657658635e66094edbcb4d"
|
||||||
|
num_commits: 1
|
||||||
|
is_draft: false
|
||||||
|
is_prerelease: true
|
||||||
|
is_tag: false
|
||||||
|
created_unix: 946684800
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
@ -173,6 +174,8 @@ type FindReleasesOptions struct {
|
||||||
ListOptions
|
ListOptions
|
||||||
IncludeDrafts bool
|
IncludeDrafts bool
|
||||||
IncludeTags bool
|
IncludeTags bool
|
||||||
|
IsPreRelease util.OptionalBool
|
||||||
|
IsDraft util.OptionalBool
|
||||||
TagNames []string
|
TagNames []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +192,12 @@ func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond {
|
||||||
if len(opts.TagNames) > 0 {
|
if len(opts.TagNames) > 0 {
|
||||||
cond = cond.And(builder.In("tag_name", opts.TagNames))
|
cond = cond.And(builder.In("tag_name", opts.TagNames))
|
||||||
}
|
}
|
||||||
|
if !opts.IsPreRelease.IsNone() {
|
||||||
|
cond = cond.And(builder.Eq{"is_prerelease": opts.IsPreRelease.IsTrue()})
|
||||||
|
}
|
||||||
|
if !opts.IsDraft.IsNone() {
|
||||||
|
cond = cond.And(builder.Eq{"is_draft": opts.IsDraft.IsTrue()})
|
||||||
|
}
|
||||||
return cond
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,6 +215,11 @@ func GetReleasesByRepoID(repoID int64, opts FindReleasesOptions) ([]*Release, er
|
||||||
return rels, sess.Find(&rels)
|
return rels, sess.Find(&rels)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountReleasesByRepoID returns a number of releases matching FindReleaseOptions and RepoID.
|
||||||
|
func CountReleasesByRepoID(repoID int64, opts FindReleasesOptions) (int64, error) {
|
||||||
|
return x.Where(opts.toConds(repoID)).Count(new(Release))
|
||||||
|
}
|
||||||
|
|
||||||
// GetLatestReleaseByRepoID returns the latest release for a repository
|
// GetLatestReleaseByRepoID returns the latest release for a repository
|
||||||
func GetLatestReleaseByRepoID(repoID int64) (*Release, error) {
|
func GetLatestReleaseByRepoID(repoID int64) (*Release, error) {
|
||||||
cond := builder.NewCond().
|
cond := builder.NewCond().
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/templates"
|
"code.gitea.io/gitea/modules/templates"
|
||||||
"code.gitea.io/gitea/modules/translation"
|
"code.gitea.io/gitea/modules/translation"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/modules/web/middleware"
|
"code.gitea.io/gitea/modules/web/middleware"
|
||||||
"code.gitea.io/gitea/services/auth"
|
"code.gitea.io/gitea/services/auth"
|
||||||
|
|
||||||
|
@ -319,6 +320,11 @@ func (ctx *Context) QueryBool(key string, defaults ...bool) bool {
|
||||||
return (*Forms)(ctx.Req).MustBool(key, defaults...)
|
return (*Forms)(ctx.Req).MustBool(key, defaults...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryOptionalBool returns request form as OptionalBool with default
|
||||||
|
func (ctx *Context) QueryOptionalBool(key string, defaults ...util.OptionalBool) util.OptionalBool {
|
||||||
|
return (*Forms)(ctx.Req).MustOptionalBool(key, defaults...)
|
||||||
|
}
|
||||||
|
|
||||||
// HandleText handles HTTP status code
|
// HandleText handles HTTP status code
|
||||||
func (ctx *Context) HandleText(status int, title string) {
|
func (ctx *Context) HandleText(status int, title string) {
|
||||||
if (status/100 == 4) || (status/100 == 5) {
|
if (status/100 == 4) || (status/100 == 5) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Forms a new enhancement of http.Request
|
// Forms a new enhancement of http.Request
|
||||||
|
@ -225,3 +226,16 @@ func (f *Forms) MustBool(key string, defaults ...bool) bool {
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MustOptionalBool returns request form as OptionalBool with default
|
||||||
|
func (f *Forms) MustOptionalBool(key string, defaults ...util.OptionalBool) util.OptionalBool {
|
||||||
|
value := (*http.Request)(f).FormValue(key)
|
||||||
|
if len(value) == 0 {
|
||||||
|
return util.OptionalBoolNone
|
||||||
|
}
|
||||||
|
v, err := strconv.ParseBool((*http.Request)(f).FormValue(key))
|
||||||
|
if len(defaults) > 0 && err != nil {
|
||||||
|
return defaults[0]
|
||||||
|
}
|
||||||
|
return util.OptionalBoolOf(v)
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
@ -83,6 +84,14 @@ func ListReleases(ctx *context.APIContext) {
|
||||||
// description: name of the repo
|
// description: name of the repo
|
||||||
// type: string
|
// type: string
|
||||||
// required: true
|
// required: true
|
||||||
|
// - name: draft
|
||||||
|
// in: query
|
||||||
|
// description: filter (exclude / include) drafts, if you dont have repo write access none will show
|
||||||
|
// type: boolean
|
||||||
|
// - name: pre-release
|
||||||
|
// in: query
|
||||||
|
// description: filter (exclude / include) pre-releases
|
||||||
|
// type: boolean
|
||||||
// - name: per_page
|
// - name: per_page
|
||||||
// in: query
|
// in: query
|
||||||
// description: page size of results, deprecated - use limit
|
// description: page size of results, deprecated - use limit
|
||||||
|
@ -100,15 +109,19 @@ func ListReleases(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/ReleaseList"
|
// "$ref": "#/responses/ReleaseList"
|
||||||
listOptions := utils.GetListOptions(ctx)
|
listOptions := utils.GetListOptions(ctx)
|
||||||
if ctx.QueryInt("per_page") != 0 {
|
if listOptions.PageSize == 0 && ctx.QueryInt("per_page") != 0 {
|
||||||
listOptions.PageSize = ctx.QueryInt("per_page")
|
listOptions.PageSize = ctx.QueryInt("per_page")
|
||||||
}
|
}
|
||||||
|
|
||||||
releases, err := models.GetReleasesByRepoID(ctx.Repo.Repository.ID, models.FindReleasesOptions{
|
opts := models.FindReleasesOptions{
|
||||||
ListOptions: listOptions,
|
ListOptions: listOptions,
|
||||||
IncludeDrafts: ctx.Repo.AccessMode >= models.AccessModeWrite,
|
IncludeDrafts: ctx.Repo.AccessMode >= models.AccessModeWrite,
|
||||||
IncludeTags: false,
|
IncludeTags: false,
|
||||||
})
|
IsDraft: ctx.QueryOptionalBool("draft"),
|
||||||
|
IsPreRelease: ctx.QueryOptionalBool("pre-release"),
|
||||||
|
}
|
||||||
|
|
||||||
|
releases, err := models.GetReleasesByRepoID(ctx.Repo.Repository.ID, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetReleasesByRepoID", err)
|
ctx.Error(http.StatusInternalServerError, "GetReleasesByRepoID", err)
|
||||||
return
|
return
|
||||||
|
@ -121,6 +134,16 @@ func ListReleases(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
rels[i] = convert.ToRelease(release)
|
rels[i] = convert.ToRelease(release)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filteredCount, err := models.CountReleasesByRepoID(ctx.Repo.Repository.ID, opts)
|
||||||
|
if err != nil {
|
||||||
|
ctx.InternalServerError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.SetLinkHeader(int(filteredCount), listOptions.PageSize)
|
||||||
|
ctx.Header().Set("X-Total-Count", fmt.Sprint(filteredCount))
|
||||||
|
ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link")
|
||||||
ctx.JSON(http.StatusOK, rels)
|
ctx.JSON(http.StatusOK, rels)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8076,6 +8076,18 @@
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "filter (exclude / include) drafts, if you dont have repo write access none will show",
|
||||||
|
"name": "draft",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "filter (exclude / include) pre-releases",
|
||||||
|
"name": "pre-release",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page size of results, deprecated - use limit",
|
"description": "page size of results, deprecated - use limit",
|
||||||
|
|
Reference in a new issue