mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-02 20:06:06 +01:00 
			
		
		
		
	Add is_archived option for issue indexer (#32735)
				
					
				
			Try to fix #32697 Reason: `is_archived` is already defined in the query options, but it is not implemented in the indexer.
This commit is contained in:
		@@ -23,7 +23,7 @@ import (
 | 
			
		||||
const (
 | 
			
		||||
	issueIndexerAnalyzer      = "issueIndexer"
 | 
			
		||||
	issueIndexerDocType       = "issueIndexerDocType"
 | 
			
		||||
	issueIndexerLatestVersion = 4
 | 
			
		||||
	issueIndexerLatestVersion = 5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const unicodeNormalizeName = "unicodeNormalize"
 | 
			
		||||
@@ -75,6 +75,7 @@ func generateIssueIndexMapping() (mapping.IndexMapping, error) {
 | 
			
		||||
 | 
			
		||||
	docMapping.AddFieldMappingsAt("is_pull", boolFieldMapping)
 | 
			
		||||
	docMapping.AddFieldMappingsAt("is_closed", boolFieldMapping)
 | 
			
		||||
	docMapping.AddFieldMappingsAt("is_archived", boolFieldMapping)
 | 
			
		||||
	docMapping.AddFieldMappingsAt("label_ids", numberFieldMapping)
 | 
			
		||||
	docMapping.AddFieldMappingsAt("no_label", boolFieldMapping)
 | 
			
		||||
	docMapping.AddFieldMappingsAt("milestone_id", numberFieldMapping)
 | 
			
		||||
@@ -185,6 +186,9 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
 | 
			
		||||
	if options.IsClosed.Has() {
 | 
			
		||||
		queries = append(queries, inner_bleve.BoolFieldQuery(options.IsClosed.Value(), "is_closed"))
 | 
			
		||||
	}
 | 
			
		||||
	if options.IsArchived.Has() {
 | 
			
		||||
		queries = append(queries, inner_bleve.BoolFieldQuery(options.IsArchived.Value(), "is_archived"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if options.NoLabelOnly {
 | 
			
		||||
		queries = append(queries, inner_bleve.BoolFieldQuery(true, "no_label"))
 | 
			
		||||
 
 | 
			
		||||
@@ -72,7 +72,7 @@ func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_m
 | 
			
		||||
		UpdatedAfterUnix:   options.UpdatedAfterUnix.Value(),
 | 
			
		||||
		UpdatedBeforeUnix:  options.UpdatedBeforeUnix.Value(),
 | 
			
		||||
		PriorityRepoID:     0,
 | 
			
		||||
		IsArchived:         optional.None[bool](),
 | 
			
		||||
		IsArchived:         options.IsArchived,
 | 
			
		||||
		Org:                nil,
 | 
			
		||||
		Team:               nil,
 | 
			
		||||
		User:               nil,
 | 
			
		||||
 
 | 
			
		||||
@@ -11,11 +11,12 @@ import (
 | 
			
		||||
 | 
			
		||||
func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOptions {
 | 
			
		||||
	searchOpt := &SearchOptions{
 | 
			
		||||
		Keyword:   keyword,
 | 
			
		||||
		RepoIDs:   opts.RepoIDs,
 | 
			
		||||
		AllPublic: opts.AllPublic,
 | 
			
		||||
		IsPull:    opts.IsPull,
 | 
			
		||||
		IsClosed:  opts.IsClosed,
 | 
			
		||||
		Keyword:    keyword,
 | 
			
		||||
		RepoIDs:    opts.RepoIDs,
 | 
			
		||||
		AllPublic:  opts.AllPublic,
 | 
			
		||||
		IsPull:     opts.IsPull,
 | 
			
		||||
		IsClosed:   opts.IsClosed,
 | 
			
		||||
		IsArchived: opts.IsArchived,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(opts.LabelIDs) == 1 && opts.LabelIDs[0] == 0 {
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	issueIndexerLatestVersion = 1
 | 
			
		||||
	issueIndexerLatestVersion = 2
 | 
			
		||||
	// multi-match-types, currently only 2 types are used
 | 
			
		||||
	// Reference: https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-multi-match-query.html#multi-match-types
 | 
			
		||||
	esMultiMatchTypeBestFields   = "best_fields"
 | 
			
		||||
@@ -58,6 +58,7 @@ const (
 | 
			
		||||
 | 
			
		||||
			"is_pull": { "type": "boolean", "index": true },
 | 
			
		||||
			"is_closed": { "type": "boolean", "index": true },
 | 
			
		||||
			"is_archived": { "type": "boolean", "index": true },
 | 
			
		||||
			"label_ids": { "type": "integer", "index": true },
 | 
			
		||||
			"no_label": { "type": "boolean", "index": true },
 | 
			
		||||
			"milestone_id": { "type": "integer", "index": true },
 | 
			
		||||
@@ -168,6 +169,9 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
 | 
			
		||||
	if options.IsClosed.Has() {
 | 
			
		||||
		query.Must(elastic.NewTermQuery("is_closed", options.IsClosed.Value()))
 | 
			
		||||
	}
 | 
			
		||||
	if options.IsArchived.Has() {
 | 
			
		||||
		query.Must(elastic.NewTermQuery("is_archived", options.IsArchived.Value()))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if options.NoLabelOnly {
 | 
			
		||||
		query.Must(elastic.NewTermQuery("no_label", true))
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,7 @@ func TestDBSearchIssues(t *testing.T) {
 | 
			
		||||
	t.Run("search issues by ID", searchIssueByID)
 | 
			
		||||
	t.Run("search issues is pr", searchIssueIsPull)
 | 
			
		||||
	t.Run("search issues is closed", searchIssueIsClosed)
 | 
			
		||||
	t.Run("search issues is archived", searchIssueIsArchived)
 | 
			
		||||
	t.Run("search issues by milestone", searchIssueByMilestoneID)
 | 
			
		||||
	t.Run("search issues by label", searchIssueByLabelID)
 | 
			
		||||
	t.Run("search issues by time", searchIssueByTime)
 | 
			
		||||
@@ -298,6 +299,33 @@ func searchIssueIsClosed(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func searchIssueIsArchived(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		opts        SearchOptions
 | 
			
		||||
		expectedIDs []int64
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			SearchOptions{
 | 
			
		||||
				IsArchived: optional.Some(false),
 | 
			
		||||
			},
 | 
			
		||||
			[]int64{22, 21, 17, 16, 15, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2, 1},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			SearchOptions{
 | 
			
		||||
				IsArchived: optional.Some(true),
 | 
			
		||||
			},
 | 
			
		||||
			[]int64{14},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
		issueIDs, _, err := SearchIssues(context.TODO(), &test.opts)
 | 
			
		||||
		if !assert.NoError(t, err) {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		assert.Equal(t, test.expectedIDs, issueIDs)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func searchIssueByMilestoneID(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		opts        SearchOptions
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ type IndexerData struct {
 | 
			
		||||
	// Fields used for filtering
 | 
			
		||||
	IsPull             bool               `json:"is_pull"`
 | 
			
		||||
	IsClosed           bool               `json:"is_closed"`
 | 
			
		||||
	IsArchived         bool               `json:"is_archived"`
 | 
			
		||||
	LabelIDs           []int64            `json:"label_ids"`
 | 
			
		||||
	NoLabel            bool               `json:"no_label"` // True if LabelIDs is empty
 | 
			
		||||
	MilestoneID        int64              `json:"milestone_id"`
 | 
			
		||||
@@ -81,8 +82,9 @@ type SearchOptions struct {
 | 
			
		||||
	RepoIDs   []int64 // repository IDs which the issues belong to
 | 
			
		||||
	AllPublic bool    // if include all public repositories
 | 
			
		||||
 | 
			
		||||
	IsPull   optional.Option[bool] // if the issues is a pull request
 | 
			
		||||
	IsClosed optional.Option[bool] // if the issues is closed
 | 
			
		||||
	IsPull     optional.Option[bool] // if the issues is a pull request
 | 
			
		||||
	IsClosed   optional.Option[bool] // if the issues is closed
 | 
			
		||||
	IsArchived optional.Option[bool] // if the repo is archived
 | 
			
		||||
 | 
			
		||||
	IncludedLabelIDs    []int64 // labels the issues have
 | 
			
		||||
	ExcludedLabelIDs    []int64 // labels the issues don't have
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	issueIndexerLatestVersion = 3
 | 
			
		||||
	issueIndexerLatestVersion = 4
 | 
			
		||||
 | 
			
		||||
	// TODO: make this configurable if necessary
 | 
			
		||||
	maxTotalHits = 10000
 | 
			
		||||
@@ -61,6 +61,7 @@ func NewIndexer(url, apiKey, indexerName string) *Indexer {
 | 
			
		||||
			"is_public",
 | 
			
		||||
			"is_pull",
 | 
			
		||||
			"is_closed",
 | 
			
		||||
			"is_archived",
 | 
			
		||||
			"label_ids",
 | 
			
		||||
			"no_label",
 | 
			
		||||
			"milestone_id",
 | 
			
		||||
@@ -145,6 +146,9 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
 | 
			
		||||
	if options.IsClosed.Has() {
 | 
			
		||||
		query.And(inner_meilisearch.NewFilterEq("is_closed", options.IsClosed.Value()))
 | 
			
		||||
	}
 | 
			
		||||
	if options.IsArchived.Has() {
 | 
			
		||||
		query.And(inner_meilisearch.NewFilterEq("is_archived", options.IsArchived.Value()))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if options.NoLabelOnly {
 | 
			
		||||
		query.And(inner_meilisearch.NewFilterEq("no_label", true))
 | 
			
		||||
 
 | 
			
		||||
@@ -101,6 +101,7 @@ func getIssueIndexerData(ctx context.Context, issueID int64) (*internal.IndexerD
 | 
			
		||||
		Comments:           comments,
 | 
			
		||||
		IsPull:             issue.IsPull,
 | 
			
		||||
		IsClosed:           issue.IsClosed,
 | 
			
		||||
		IsArchived:         issue.Repo.IsArchived,
 | 
			
		||||
		LabelIDs:           labels,
 | 
			
		||||
		NoLabel:            len(labels) == 0,
 | 
			
		||||
		MilestoneID:        issue.MilestoneID,
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/base"
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/indexer/code"
 | 
			
		||||
	issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
 | 
			
		||||
	"code.gitea.io/gitea/modules/indexer/stats"
 | 
			
		||||
	"code.gitea.io/gitea/modules/lfs"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
@@ -905,6 +906,9 @@ func SettingsPost(ctx *context.Context) {
 | 
			
		||||
			log.Error("CleanRepoScheduleTasks for archived repo %s/%s: %v", ctx.Repo.Owner.Name, repo.Name, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// update issue indexer
 | 
			
		||||
		issue_indexer.UpdateRepoIndexer(ctx, repo.ID)
 | 
			
		||||
 | 
			
		||||
		ctx.Flash.Success(ctx.Tr("repo.settings.archive.success"))
 | 
			
		||||
 | 
			
		||||
		log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
 | 
			
		||||
@@ -929,6 +933,9 @@ func SettingsPost(ctx *context.Context) {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// update issue indexer
 | 
			
		||||
		issue_indexer.UpdateRepoIndexer(ctx, repo.ID)
 | 
			
		||||
 | 
			
		||||
		ctx.Flash.Success(ctx.Tr("repo.settings.unarchive.success"))
 | 
			
		||||
 | 
			
		||||
		log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user