Fix milestones too many SQL variables bug (#10880)
* Fix milestones too many SQL variables bug * Fix test * Don't display repositories with no milestone and fix tests * Remove unused code and add some comments
This commit is contained in:
parent
bf847b9397
commit
73cf0e2614
5 changed files with 135 additions and 105 deletions
|
@ -525,10 +525,12 @@ func DeleteMilestoneByRepoID(repoID, id int64) error {
|
||||||
return sess.Commit()
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountMilestonesByRepoIDs map from repoIDs to number of milestones matching the options`
|
// CountMilestones map from repo conditions to number of milestones matching the options`
|
||||||
func CountMilestonesByRepoIDs(repoIDs []int64, isClosed bool) (map[int64]int64, error) {
|
func CountMilestones(repoCond builder.Cond, isClosed bool) (map[int64]int64, error) {
|
||||||
sess := x.Where("is_closed = ?", isClosed)
|
sess := x.Where("is_closed = ?", isClosed)
|
||||||
sess.In("repo_id", repoIDs)
|
if repoCond.IsValid() {
|
||||||
|
sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
|
||||||
|
}
|
||||||
|
|
||||||
countsSlice := make([]*struct {
|
countsSlice := make([]*struct {
|
||||||
RepoID int64
|
RepoID int64
|
||||||
|
@ -548,11 +550,21 @@ func CountMilestonesByRepoIDs(repoIDs []int64, isClosed bool) (map[int64]int64,
|
||||||
return countMap, nil
|
return countMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMilestonesByRepoIDs returns a list of milestones of given repositories and status.
|
// CountMilestonesByRepoIDs map from repoIDs to number of milestones matching the options`
|
||||||
func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType string) (MilestoneList, error) {
|
func CountMilestonesByRepoIDs(repoIDs []int64, isClosed bool) (map[int64]int64, error) {
|
||||||
|
return CountMilestones(
|
||||||
|
builder.In("repo_id", repoIDs),
|
||||||
|
isClosed,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchMilestones search milestones
|
||||||
|
func SearchMilestones(repoCond builder.Cond, page int, isClosed bool, sortType string) (MilestoneList, error) {
|
||||||
miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
|
miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
|
||||||
sess := x.Where("is_closed = ?", isClosed)
|
sess := x.Where("is_closed = ?", isClosed)
|
||||||
sess.In("repo_id", repoIDs)
|
if repoCond.IsValid() {
|
||||||
|
sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond))
|
||||||
|
}
|
||||||
if page > 0 {
|
if page > 0 {
|
||||||
sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
|
sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
|
||||||
}
|
}
|
||||||
|
@ -574,25 +586,45 @@ func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType s
|
||||||
return miles, sess.Find(&miles)
|
return miles, sess.Find(&miles)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetMilestonesByRepoIDs returns a list of milestones of given repositories and status.
|
||||||
|
func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType string) (MilestoneList, error) {
|
||||||
|
return SearchMilestones(
|
||||||
|
builder.In("repo_id", repoIDs),
|
||||||
|
page,
|
||||||
|
isClosed,
|
||||||
|
sortType,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// MilestonesStats represents milestone statistic information.
|
// MilestonesStats represents milestone statistic information.
|
||||||
type MilestonesStats struct {
|
type MilestonesStats struct {
|
||||||
OpenCount, ClosedCount int64
|
OpenCount, ClosedCount int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Total returns the total counts of milestones
|
||||||
|
func (m MilestonesStats) Total() int64 {
|
||||||
|
return m.OpenCount + m.ClosedCount
|
||||||
|
}
|
||||||
|
|
||||||
// GetMilestonesStats returns milestone statistic information for dashboard by given conditions.
|
// GetMilestonesStats returns milestone statistic information for dashboard by given conditions.
|
||||||
func GetMilestonesStats(userRepoIDs []int64) (*MilestonesStats, error) {
|
func GetMilestonesStats(repoCond builder.Cond) (*MilestonesStats, error) {
|
||||||
var err error
|
var err error
|
||||||
stats := &MilestonesStats{}
|
stats := &MilestonesStats{}
|
||||||
|
|
||||||
stats.OpenCount, err = x.Where("is_closed = ?", false).
|
sess := x.Where("is_closed = ?", false)
|
||||||
And(builder.In("repo_id", userRepoIDs)).
|
if repoCond.IsValid() {
|
||||||
Count(new(Milestone))
|
sess.And(builder.In("repo_id", builder.Select("id").From("repository").Where(repoCond)))
|
||||||
|
}
|
||||||
|
stats.OpenCount, err = sess.Count(new(Milestone))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
stats.ClosedCount, err = x.Where("is_closed = ?", true).
|
|
||||||
And(builder.In("repo_id", userRepoIDs)).
|
sess = x.Where("is_closed = ?", true)
|
||||||
Count(new(Milestone))
|
if repoCond.IsValid() {
|
||||||
|
sess.And(builder.In("repo_id", builder.Select("id").From("repository").Where(repoCond)))
|
||||||
|
}
|
||||||
|
stats.ClosedCount, err = sess.Count(new(Milestone))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
"xorm.io/builder"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -370,7 +371,7 @@ func TestGetMilestonesStats(t *testing.T) {
|
||||||
repo1 := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
repo1 := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||||
repo2 := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
|
repo2 := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
|
||||||
|
|
||||||
milestoneStats, err := GetMilestonesStats([]int64{repo1.ID, repo2.ID})
|
milestoneStats, err := GetMilestonesStats(builder.In("repo_id", []int64{repo1.ID, repo2.ID}))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, repo1.NumOpenMilestones+repo2.NumOpenMilestones, milestoneStats.OpenCount)
|
assert.EqualValues(t, repo1.NumOpenMilestones+repo2.NumOpenMilestones, milestoneStats.OpenCount)
|
||||||
assert.EqualValues(t, repo1.NumClosedMilestones+repo2.NumClosedMilestones, milestoneStats.ClosedCount)
|
assert.EqualValues(t, repo1.NumClosedMilestones+repo2.NumClosedMilestones, milestoneStats.ClosedCount)
|
||||||
|
|
|
@ -163,6 +163,10 @@ type SearchRepoOptions struct {
|
||||||
TopicOnly bool
|
TopicOnly bool
|
||||||
// include description in keyword search
|
// include description in keyword search
|
||||||
IncludeDescription bool
|
IncludeDescription bool
|
||||||
|
// None -> include has milestones AND has no milestone
|
||||||
|
// True -> include just has milestones
|
||||||
|
// False -> include just has no milestone
|
||||||
|
HasMilestones util.OptionalBool
|
||||||
}
|
}
|
||||||
|
|
||||||
//SearchOrderBy is used to sort the result
|
//SearchOrderBy is used to sort the result
|
||||||
|
@ -294,6 +298,14 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
|
||||||
if opts.Actor != nil && opts.Actor.IsRestricted {
|
if opts.Actor != nil && opts.Actor.IsRestricted {
|
||||||
cond = cond.And(accessibleRepositoryCondition(opts.Actor))
|
cond = cond.And(accessibleRepositoryCondition(opts.Actor))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch opts.HasMilestones {
|
||||||
|
case util.OptionalBoolTrue:
|
||||||
|
cond = cond.And(builder.Gt{"num_milestones": 0})
|
||||||
|
case util.OptionalBoolFalse:
|
||||||
|
cond = cond.And(builder.Eq{"num_milestones": 0}.Or(builder.IsNull{"num_milestones"}))
|
||||||
|
}
|
||||||
|
|
||||||
return cond
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,7 +313,11 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
|
||||||
// it returns results in given range and number of total results.
|
// it returns results in given range and number of total results.
|
||||||
func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||||
cond := SearchRepositoryCondition(opts)
|
cond := SearchRepositoryCondition(opts)
|
||||||
|
return SearchRepositoryByCondition(opts, cond, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchRepositoryByCondition search repositories by condition
|
||||||
|
func SearchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) {
|
||||||
if opts.Page <= 0 {
|
if opts.Page <= 0 {
|
||||||
opts.Page = 1
|
opts.Page = 1
|
||||||
}
|
}
|
||||||
|
@ -326,16 +342,18 @@ func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
repos := make(RepositoryList, 0, opts.PageSize)
|
repos := make(RepositoryList, 0, opts.PageSize)
|
||||||
if err = sess.
|
sess.Where(cond).OrderBy(opts.OrderBy.String())
|
||||||
Where(cond).
|
if opts.PageSize > 0 {
|
||||||
OrderBy(opts.OrderBy.String()).
|
sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
|
||||||
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
|
}
|
||||||
Find(&repos); err != nil {
|
if err = sess.Find(&repos); err != nil {
|
||||||
return nil, 0, fmt.Errorf("Repo: %v", err)
|
return nil, 0, fmt.Errorf("Repo: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = repos.loadAttributes(sess); err != nil {
|
if loadAttributes {
|
||||||
return nil, 0, fmt.Errorf("LoadAttributes: %v", err)
|
if err = repos.loadAttributes(sess); err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("LoadAttributes: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return repos, count, nil
|
return repos, count, nil
|
||||||
|
|
|
@ -25,7 +25,7 @@ import (
|
||||||
|
|
||||||
"github.com/keybase/go-crypto/openpgp"
|
"github.com/keybase/go-crypto/openpgp"
|
||||||
"github.com/keybase/go-crypto/openpgp/armor"
|
"github.com/keybase/go-crypto/openpgp/armor"
|
||||||
"github.com/unknwon/com"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -173,135 +173,114 @@ func Milestones(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sortType := ctx.Query("sort")
|
var (
|
||||||
page := ctx.QueryInt("page")
|
repoOpts = models.SearchRepoOptions{
|
||||||
|
Actor: ctxUser,
|
||||||
|
OwnerID: ctxUser.ID,
|
||||||
|
Private: true,
|
||||||
|
AllPublic: false, // Include also all public repositories of users and public organisations
|
||||||
|
AllLimited: false, // Include also all public repositories of limited organisations
|
||||||
|
HasMilestones: util.OptionalBoolTrue, // Just needs display repos has milestones
|
||||||
|
}
|
||||||
|
|
||||||
|
userRepoCond = models.SearchRepositoryCondition(&repoOpts) // all repo condition user could visit
|
||||||
|
repoCond = userRepoCond
|
||||||
|
repoIDs []int64
|
||||||
|
|
||||||
|
reposQuery = ctx.Query("repos")
|
||||||
|
isShowClosed = ctx.Query("state") == "closed"
|
||||||
|
sortType = ctx.Query("sort")
|
||||||
|
page = ctx.QueryInt("page")
|
||||||
|
)
|
||||||
|
|
||||||
if page <= 1 {
|
if page <= 1 {
|
||||||
page = 1
|
page = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
reposQuery := ctx.Query("repos")
|
|
||||||
isShowClosed := ctx.Query("state") == "closed"
|
|
||||||
|
|
||||||
// Get repositories.
|
|
||||||
var err error
|
|
||||||
var userRepoIDs []int64
|
|
||||||
if ctxUser.IsOrganization() {
|
|
||||||
env, err := ctxUser.AccessibleReposEnv(ctx.User.ID)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("AccessibleReposEnv", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userRepoIDs, err = env.RepoIDs(1, ctxUser.NumRepos)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("env.RepoIDs", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userRepoIDs, err = models.FilterOutRepoIdsWithoutUnitAccess(ctx.User, userRepoIDs, models.UnitTypeIssues, models.UnitTypePullRequests)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("FilterOutRepoIdsWithoutUnitAccess", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
userRepoIDs, err = ctxUser.GetAccessRepoIDs(models.UnitTypeIssues, models.UnitTypePullRequests)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("ctxUser.GetAccessRepoIDs", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(userRepoIDs) == 0 {
|
|
||||||
userRepoIDs = []int64{-1}
|
|
||||||
}
|
|
||||||
|
|
||||||
var repoIDs []int64
|
|
||||||
if len(reposQuery) != 0 {
|
if len(reposQuery) != 0 {
|
||||||
if issueReposQueryPattern.MatchString(reposQuery) {
|
if issueReposQueryPattern.MatchString(reposQuery) {
|
||||||
// remove "[" and "]" from string
|
// remove "[" and "]" from string
|
||||||
reposQuery = reposQuery[1 : len(reposQuery)-1]
|
reposQuery = reposQuery[1 : len(reposQuery)-1]
|
||||||
//for each ID (delimiter ",") add to int to repoIDs
|
//for each ID (delimiter ",") add to int to repoIDs
|
||||||
reposSet := false
|
|
||||||
for _, rID := range strings.Split(reposQuery, ",") {
|
for _, rID := range strings.Split(reposQuery, ",") {
|
||||||
// Ensure nonempty string entries
|
// Ensure nonempty string entries
|
||||||
if rID != "" && rID != "0" {
|
if rID != "" && rID != "0" {
|
||||||
reposSet = true
|
|
||||||
rIDint64, err := strconv.ParseInt(rID, 10, 64)
|
rIDint64, err := strconv.ParseInt(rID, 10, 64)
|
||||||
// If the repo id specified by query is not parseable or not accessible by user, just ignore it.
|
// If the repo id specified by query is not parseable or not accessible by user, just ignore it.
|
||||||
if err == nil && com.IsSliceContainsInt64(userRepoIDs, rIDint64) {
|
if err == nil {
|
||||||
repoIDs = append(repoIDs, rIDint64)
|
repoIDs = append(repoIDs, rIDint64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if reposSet && len(repoIDs) == 0 {
|
if len(repoIDs) > 0 {
|
||||||
// force an empty result
|
// Don't just let repoCond = builder.In("id", repoIDs) because user may has no permission on repoIDs
|
||||||
repoIDs = []int64{-1}
|
// But the original repoCond has a limitation
|
||||||
|
repoCond = repoCond.And(builder.In("id", repoIDs))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Warn("issueReposQueryPattern not match with query")
|
log.Warn("issueReposQueryPattern not match with query")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(repoIDs) == 0 {
|
counts, err := models.CountMilestones(userRepoCond, isShowClosed)
|
||||||
repoIDs = userRepoIDs
|
|
||||||
}
|
|
||||||
|
|
||||||
counts, err := models.CountMilestonesByRepoIDs(userRepoIDs, isShowClosed)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("CountMilestonesByRepoIDs", err)
|
ctx.ServerError("CountMilestonesByRepoIDs", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
milestones, err := models.GetMilestonesByRepoIDs(repoIDs, page, isShowClosed, sortType)
|
milestones, err := models.SearchMilestones(repoCond, page, isShowClosed, sortType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetMilestonesByRepoIDs", err)
|
ctx.ServerError("GetMilestonesByRepoIDs", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
showReposMap := make(map[int64]*models.Repository, len(counts))
|
showRepos, _, err := models.SearchRepositoryByCondition(&repoOpts, userRepoCond, false)
|
||||||
for rID := range counts {
|
if err != nil {
|
||||||
if rID == -1 {
|
ctx.ServerError("SearchRepositoryByCondition", err)
|
||||||
break
|
|
||||||
}
|
|
||||||
repo, err := models.GetRepositoryByID(rID)
|
|
||||||
if err != nil {
|
|
||||||
if models.IsErrRepoNotExist(err) {
|
|
||||||
ctx.NotFound("GetRepositoryByID", err)
|
|
||||||
return
|
|
||||||
} else if err != nil {
|
|
||||||
ctx.ServerError("GetRepositoryByID", fmt.Errorf("[%d]%v", rID, err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showReposMap[rID] = repo
|
|
||||||
}
|
|
||||||
|
|
||||||
showRepos := models.RepositoryListOfMap(showReposMap)
|
|
||||||
sort.Sort(showRepos)
|
|
||||||
if err = showRepos.LoadAttributes(); err != nil {
|
|
||||||
ctx.ServerError("LoadAttributes", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
sort.Sort(showRepos)
|
||||||
|
|
||||||
for _, m := range milestones {
|
for i := 0; i < len(milestones); {
|
||||||
m.Repo = showReposMap[m.RepoID]
|
for _, repo := range showRepos {
|
||||||
m.RenderedContent = string(markdown.Render([]byte(m.Content), m.Repo.Link(), m.Repo.ComposeMetas()))
|
if milestones[i].RepoID == repo.ID {
|
||||||
if m.Repo.IsTimetrackerEnabled() {
|
milestones[i].Repo = repo
|
||||||
err := m.LoadTotalTrackedTime()
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if milestones[i].Repo == nil {
|
||||||
|
log.Warn("Cannot find milestone %d 's repository %d", milestones[i].ID, milestones[i].RepoID)
|
||||||
|
milestones = append(milestones[:i], milestones[i+1:]...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
milestones[i].RenderedContent = string(markdown.Render([]byte(milestones[i].Content), milestones[i].Repo.Link(), milestones[i].Repo.ComposeMetas()))
|
||||||
|
if milestones[i].Repo.IsTimetrackerEnabled() {
|
||||||
|
err := milestones[i].LoadTotalTrackedTime()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("LoadTotalTrackedTime", err)
|
ctx.ServerError("LoadTotalTrackedTime", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
milestoneStats, err := models.GetMilestonesStats(repoIDs)
|
milestoneStats, err := models.GetMilestonesStats(repoCond)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetMilestoneStats", err)
|
ctx.ServerError("GetMilestoneStats", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
totalMilestoneStats, err := models.GetMilestonesStats(userRepoIDs)
|
var totalMilestoneStats *models.MilestonesStats
|
||||||
if err != nil {
|
if len(repoIDs) == 0 {
|
||||||
ctx.ServerError("GetMilestoneStats", err)
|
totalMilestoneStats = milestoneStats
|
||||||
return
|
} else {
|
||||||
|
totalMilestoneStats, err = models.GetMilestonesStats(userRepoCond)
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("GetMilestoneStats", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pagerCount int
|
var pagerCount int
|
||||||
|
@ -320,7 +299,7 @@ func Milestones(ctx *context.Context) {
|
||||||
ctx.Data["Counts"] = counts
|
ctx.Data["Counts"] = counts
|
||||||
ctx.Data["MilestoneStats"] = milestoneStats
|
ctx.Data["MilestoneStats"] = milestoneStats
|
||||||
ctx.Data["SortType"] = sortType
|
ctx.Data["SortType"] = sortType
|
||||||
if len(repoIDs) != len(userRepoIDs) {
|
if milestoneStats.Total() != totalMilestoneStats.Total() {
|
||||||
ctx.Data["RepoIDs"] = repoIDs
|
ctx.Data["RepoIDs"] = repoIDs
|
||||||
}
|
}
|
||||||
ctx.Data["IsShowClosed"] = isShowClosed
|
ctx.Data["IsShowClosed"] = isShowClosed
|
||||||
|
|
|
@ -48,7 +48,7 @@ func TestMilestones(t *testing.T) {
|
||||||
assert.EqualValues(t, "furthestduedate", ctx.Data["SortType"])
|
assert.EqualValues(t, "furthestduedate", ctx.Data["SortType"])
|
||||||
assert.EqualValues(t, 1, ctx.Data["Total"])
|
assert.EqualValues(t, 1, ctx.Data["Total"])
|
||||||
assert.Len(t, ctx.Data["Milestones"], 1)
|
assert.Len(t, ctx.Data["Milestones"], 1)
|
||||||
assert.Len(t, ctx.Data["Repos"], 1)
|
assert.Len(t, ctx.Data["Repos"], 2) // both repo 42 and 1 have milestones and both are owned by user 2
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMilestonesForSpecificRepo(t *testing.T) {
|
func TestMilestonesForSpecificRepo(t *testing.T) {
|
||||||
|
@ -68,5 +68,5 @@ func TestMilestonesForSpecificRepo(t *testing.T) {
|
||||||
assert.EqualValues(t, "furthestduedate", ctx.Data["SortType"])
|
assert.EqualValues(t, "furthestduedate", ctx.Data["SortType"])
|
||||||
assert.EqualValues(t, 1, ctx.Data["Total"])
|
assert.EqualValues(t, 1, ctx.Data["Total"])
|
||||||
assert.Len(t, ctx.Data["Milestones"], 1)
|
assert.Len(t, ctx.Data["Milestones"], 1)
|
||||||
assert.Len(t, ctx.Data["Repos"], 1)
|
assert.Len(t, ctx.Data["Repos"], 2) // both repo 42 and 1 have milestones and both are owned by user 2
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue