Skip to content

Commit 184e068

Browse files
virtulisGusted
authored andcommitted
feat: show more relevant results for 'dependencies' dropdown (#8003)
- Fix issue dropdown breaking when currently selected issue is included in results. - Add `sort` parameter to `/issues/search` API. - Sort dropdown by relevance. - Make priority_repo_id work again. - Added E2E test. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8003 Reviewed-by: Shiny Nematoda <[email protected]> Reviewed-by: Gusted <[email protected]> Co-authored-by: Danko Aleksejevs <[email protected]> Co-committed-by: Danko Aleksejevs <[email protected]>
1 parent 414199f commit 184e068

File tree

17 files changed

+269
-41
lines changed

17 files changed

+269
-41
lines changed

models/fixtures/repository.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
created_unix: 1731254961
3333
updated_unix: 1731254961
3434
topics: '[]'
35-
35+
3636
-
3737
id: 2
3838
owner_id: 2

models/issues/issue_search.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ type IssuesOptions struct { //nolint
4848
UpdatedBeforeUnix int64
4949
// prioritize issues from this repo
5050
PriorityRepoID int64
51-
IsArchived optional.Option[bool]
51+
// if this issue index (not ID) exists and matches the filters, *and* priorityrepo sort is used, show it first
52+
PriorityIssueIndex int64
53+
IsArchived optional.Option[bool]
5254

5355
// If combined with AllPublic, then private as well as public issues
5456
// that matches the criteria will be returned, if AllPublic is false
@@ -60,7 +62,7 @@ type IssuesOptions struct { //nolint
6062

6163
// applySorts sort an issues-related session based on the provided
6264
// sortType string
63-
func applySorts(sess *xorm.Session, sortType string, priorityRepoID int64) {
65+
func applySorts(sess *xorm.Session, sortType string, priorityRepoID, priorityIssueIndex int64) {
6466
switch sortType {
6567
case "oldest":
6668
sess.Asc("issue.created_unix").Asc("issue.id")
@@ -97,8 +99,11 @@ func applySorts(sess *xorm.Session, sortType string, priorityRepoID int64) {
9799
case "priorityrepo":
98100
sess.OrderBy("CASE "+
99101
"WHEN issue.repo_id = ? THEN 1 "+
100-
"ELSE 2 END ASC", priorityRepoID).
101-
Desc("issue.created_unix").
102+
"ELSE 2 END ASC", priorityRepoID)
103+
if priorityIssueIndex != 0 {
104+
sess.OrderBy("issue.index = ? DESC", priorityIssueIndex)
105+
}
106+
sess.Desc("issue.created_unix").
102107
Desc("issue.id")
103108
case "project-column-sorting":
104109
sess.Asc("project_issue.sorting").Desc("issue.created_unix").Desc("issue.id")
@@ -470,7 +475,7 @@ func Issues(ctx context.Context, opts *IssuesOptions) (IssueList, error) {
470475
Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
471476
applyLimit(sess, opts)
472477
applyConditions(sess, opts)
473-
applySorts(sess, opts.SortType, opts.PriorityRepoID)
478+
applySorts(sess, opts.SortType, opts.PriorityRepoID, opts.PriorityIssueIndex)
474479

475480
issues := IssueList{}
476481
if err := sess.Find(&issues); err != nil {
@@ -494,7 +499,7 @@ func IssueIDs(ctx context.Context, opts *IssuesOptions, otherConds ...builder.Co
494499
}
495500

496501
applyLimit(sess, opts)
497-
applySorts(sess, opts.SortType, opts.PriorityRepoID)
502+
applySorts(sess, opts.SortType, opts.PriorityRepoID, opts.PriorityIssueIndex)
498503

499504
var res []int64
500505
total, err := sess.Select("`issue`.id").Table(&Issue{}).FindAndCount(&res)

models/issues/pull_list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ func PullRequests(ctx context.Context, baseRepoID int64, opts *PullRequestsOptio
149149
}
150150

151151
findSession := listPullRequestStatement(ctx, baseRepoID, opts)
152-
applySorts(findSession, opts.SortType, 0)
152+
applySorts(findSession, opts.SortType, 0, 0)
153153
findSession = db.SetSessionPagination(findSession, opts)
154154
prs := make([]*PullRequest, 0, opts.PageSize)
155155
found := findSession.Find(&prs)

modules/indexer/issues/bleve/bleve.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
170170

171171
if issueID, err := token.ParseIssueReference(); err == nil {
172172
idQuery := inner_bleve.NumericEqualityQuery(issueID, "index")
173-
idQuery.SetBoost(5.0)
173+
idQuery.SetBoost(20.0)
174174
innerQ.AddQuery(idQuery)
175175
}
176176

@@ -197,6 +197,15 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
197197
queries = append(queries, bleve.NewDisjunctionQuery(repoQueries...))
198198
}
199199

200+
if options.PriorityRepoID.Has() {
201+
eq := inner_bleve.NumericEqualityQuery(options.PriorityRepoID.Value(), "repo_id")
202+
eq.SetBoost(10.0)
203+
meh := bleve.NewMatchAllQuery()
204+
meh.SetBoost(0)
205+
should := bleve.NewDisjunctionQuery(eq, meh)
206+
queries = append(queries, should)
207+
}
208+
200209
if options.IsPull.Has() {
201210
queries = append(queries, inner_bleve.BoolFieldQuery(options.IsPull.Value(), "is_pull"))
202211
}

modules/indexer/issues/db/db.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ func (i *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
5353

5454
cond := builder.NewCond()
5555

56+
var priorityIssueIndex int64
5657
if options.Keyword != "" {
5758
repoCond := builder.In("repo_id", options.RepoIDs)
5859
if len(options.RepoIDs) == 1 {
@@ -82,13 +83,15 @@ func (i *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
8283
builder.Eq{"`index`": issueID},
8384
cond,
8485
)
86+
priorityIssueIndex = issueID
8587
}
8688
}
8789

8890
opt, err := ToDBOptions(ctx, options)
8991
if err != nil {
9092
return nil, err
9193
}
94+
opt.PriorityIssueIndex = priorityIssueIndex
9295

9396
// If pagesize == 0, return total count only. It's a special case for search count.
9497
if options.Paginator != nil && options.Paginator.PageSize == 0 {

modules/indexer/issues/db/options.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_m
7878
User: nil,
7979
}
8080

81+
if options.PriorityRepoID.Has() {
82+
opts.SortType = "priorityrepo"
83+
opts.PriorityRepoID = options.PriorityRepoID.Value()
84+
}
85+
8186
if len(options.MilestoneIDs) == 1 && options.MilestoneIDs[0] == 0 {
8287
opts.MilestoneIDs = []int64{db.NoConditionID}
8388
} else {

modules/indexer/issues/elasticsearch/elasticsearch.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
165165
}
166166
var eitherQ elastic.Query = innerQ
167167
if issueID, err := token.ParseIssueReference(); err == nil {
168-
indexQ := elastic.NewTermQuery("index", issueID).Boost(15.0)
168+
indexQ := elastic.NewTermQuery("index", issueID).Boost(20)
169169
eitherQ = elastic.NewDisMaxQuery().Query(indexQ).Query(innerQ).TieBreaker(0.5)
170170
}
171171
switch token.Kind {
@@ -188,6 +188,10 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
188188
}
189189
query.Must(q)
190190
}
191+
if options.PriorityRepoID.Has() {
192+
q := elastic.NewTermQuery("repo_id", options.PriorityRepoID.Value()).Boost(10)
193+
query.Should(q)
194+
}
191195

192196
if options.IsPull.Has() {
193197
query.Must(elastic.NewTermQuery("is_pull", options.IsPull.Value()))

modules/indexer/issues/internal/model.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,9 @@ type SearchResult struct {
7575
type SearchOptions struct {
7676
Keyword string // keyword to search
7777

78-
RepoIDs []int64 // repository IDs which the issues belong to
79-
AllPublic bool // if include all public repositories
78+
RepoIDs []int64 // repository IDs which the issues belong to
79+
AllPublic bool // if include all public repositories
80+
PriorityRepoID optional.Option[int64] // issues from this repository will be prioritized when SortByScore
8081

8182
IsPull optional.Option[bool] // if the issues is a pull request
8283
IsClosed optional.Option[bool] // if the issues is closed

modules/indexer/issues/internal/tests/tests.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,25 @@ var cases = []*testIndexerCase{
742742
}
743743
},
744744
},
745+
{
746+
Name: "PriorityRepoID",
747+
SearchOptions: &internal.SearchOptions{
748+
IsPull: optional.Some(false),
749+
IsClosed: optional.Some(false),
750+
PriorityRepoID: optional.Some(int64(3)),
751+
Paginator: &db.ListOptionsAll,
752+
SortBy: internal.SortByScore,
753+
},
754+
Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
755+
for i, v := range result.Hits {
756+
if i < 7 {
757+
assert.Equal(t, int64(3), data[v.ID].RepoID)
758+
} else {
759+
assert.NotEqual(t, int64(3), data[v.ID].RepoID)
760+
}
761+
}
762+
},
763+
},
745764
}
746765

747766
type testIndexerCase struct {

routers/api/v1/repo/issue.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ func SearchIssues(ctx *context.APIContext) {
121121
// description: Number of items per page
122122
// type: integer
123123
// minimum: 0
124+
// - name: sort
125+
// in: query
126+
// description: Type of sort
127+
// type: string
128+
// enum: [relevance, latest, oldest, recentupdate, leastupdate, mostcomment, leastcomment, nearduedate, farduedate]
129+
// default: latest
124130
// responses:
125131
// "200":
126132
// "$ref": "#/responses/IssueList"
@@ -276,7 +282,7 @@ func SearchIssues(ctx *context.APIContext) {
276282
IsClosed: isClosed,
277283
IncludedAnyLabelIDs: includedAnyLabels,
278284
MilestoneIDs: includedMilestones,
279-
SortBy: issue_indexer.SortByCreatedDesc,
285+
SortBy: issue_indexer.ParseSortBy(ctx.FormString("sort"), issue_indexer.SortByCreatedDesc),
280286
}
281287

282288
if since != 0 {
@@ -305,9 +311,10 @@ func SearchIssues(ctx *context.APIContext) {
305311
}
306312
}
307313

308-
// FIXME: It's unsupported to sort by priority repo when searching by indexer,
309-
// it's indeed an regression, but I think it is worth to support filtering by indexer first.
310-
_ = ctx.FormInt64("priority_repo_id")
314+
priorityRepoID := ctx.FormInt64("priority_repo_id")
315+
if priorityRepoID > 0 {
316+
searchOpt.PriorityRepoID = optional.Some(priorityRepoID)
317+
}
311318

312319
ids, total, err := issue_indexer.SearchIssues(ctx, searchOpt)
313320
if err != nil {

0 commit comments

Comments
 (0)