mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 19:06:18 +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 ( | const ( | ||||||
| 	issueIndexerAnalyzer      = "issueIndexer" | 	issueIndexerAnalyzer      = "issueIndexer" | ||||||
| 	issueIndexerDocType       = "issueIndexerDocType" | 	issueIndexerDocType       = "issueIndexerDocType" | ||||||
| 	issueIndexerLatestVersion = 4 | 	issueIndexerLatestVersion = 5 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const unicodeNormalizeName = "unicodeNormalize" | const unicodeNormalizeName = "unicodeNormalize" | ||||||
| @@ -75,6 +75,7 @@ func generateIssueIndexMapping() (mapping.IndexMapping, error) { | |||||||
|  |  | ||||||
| 	docMapping.AddFieldMappingsAt("is_pull", boolFieldMapping) | 	docMapping.AddFieldMappingsAt("is_pull", boolFieldMapping) | ||||||
| 	docMapping.AddFieldMappingsAt("is_closed", boolFieldMapping) | 	docMapping.AddFieldMappingsAt("is_closed", boolFieldMapping) | ||||||
|  | 	docMapping.AddFieldMappingsAt("is_archived", boolFieldMapping) | ||||||
| 	docMapping.AddFieldMappingsAt("label_ids", numberFieldMapping) | 	docMapping.AddFieldMappingsAt("label_ids", numberFieldMapping) | ||||||
| 	docMapping.AddFieldMappingsAt("no_label", boolFieldMapping) | 	docMapping.AddFieldMappingsAt("no_label", boolFieldMapping) | ||||||
| 	docMapping.AddFieldMappingsAt("milestone_id", numberFieldMapping) | 	docMapping.AddFieldMappingsAt("milestone_id", numberFieldMapping) | ||||||
| @@ -185,6 +186,9 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( | |||||||
| 	if options.IsClosed.Has() { | 	if options.IsClosed.Has() { | ||||||
| 		queries = append(queries, inner_bleve.BoolFieldQuery(options.IsClosed.Value(), "is_closed")) | 		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 { | 	if options.NoLabelOnly { | ||||||
| 		queries = append(queries, inner_bleve.BoolFieldQuery(true, "no_label")) | 		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(), | 		UpdatedAfterUnix:   options.UpdatedAfterUnix.Value(), | ||||||
| 		UpdatedBeforeUnix:  options.UpdatedBeforeUnix.Value(), | 		UpdatedBeforeUnix:  options.UpdatedBeforeUnix.Value(), | ||||||
| 		PriorityRepoID:     0, | 		PriorityRepoID:     0, | ||||||
| 		IsArchived:         optional.None[bool](), | 		IsArchived:         options.IsArchived, | ||||||
| 		Org:                nil, | 		Org:                nil, | ||||||
| 		Team:               nil, | 		Team:               nil, | ||||||
| 		User:               nil, | 		User:               nil, | ||||||
|   | |||||||
| @@ -11,11 +11,12 @@ import ( | |||||||
|  |  | ||||||
| func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOptions { | func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOptions { | ||||||
| 	searchOpt := &SearchOptions{ | 	searchOpt := &SearchOptions{ | ||||||
| 		Keyword:   keyword, | 		Keyword:    keyword, | ||||||
| 		RepoIDs:   opts.RepoIDs, | 		RepoIDs:    opts.RepoIDs, | ||||||
| 		AllPublic: opts.AllPublic, | 		AllPublic:  opts.AllPublic, | ||||||
| 		IsPull:    opts.IsPull, | 		IsPull:     opts.IsPull, | ||||||
| 		IsClosed:  opts.IsClosed, | 		IsClosed:   opts.IsClosed, | ||||||
|  | 		IsArchived: opts.IsArchived, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if len(opts.LabelIDs) == 1 && opts.LabelIDs[0] == 0 { | 	if len(opts.LabelIDs) == 1 && opts.LabelIDs[0] == 0 { | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	issueIndexerLatestVersion = 1 | 	issueIndexerLatestVersion = 2 | ||||||
| 	// multi-match-types, currently only 2 types are used | 	// 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 | 	// Reference: https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-multi-match-query.html#multi-match-types | ||||||
| 	esMultiMatchTypeBestFields   = "best_fields" | 	esMultiMatchTypeBestFields   = "best_fields" | ||||||
| @@ -58,6 +58,7 @@ const ( | |||||||
|  |  | ||||||
| 			"is_pull": { "type": "boolean", "index": true }, | 			"is_pull": { "type": "boolean", "index": true }, | ||||||
| 			"is_closed": { "type": "boolean", "index": true }, | 			"is_closed": { "type": "boolean", "index": true }, | ||||||
|  | 			"is_archived": { "type": "boolean", "index": true }, | ||||||
| 			"label_ids": { "type": "integer", "index": true }, | 			"label_ids": { "type": "integer", "index": true }, | ||||||
| 			"no_label": { "type": "boolean", "index": true }, | 			"no_label": { "type": "boolean", "index": true }, | ||||||
| 			"milestone_id": { "type": "integer", "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() { | 	if options.IsClosed.Has() { | ||||||
| 		query.Must(elastic.NewTermQuery("is_closed", options.IsClosed.Value())) | 		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 { | 	if options.NoLabelOnly { | ||||||
| 		query.Must(elastic.NewTermQuery("no_label", true)) | 		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 by ID", searchIssueByID) | ||||||
| 	t.Run("search issues is pr", searchIssueIsPull) | 	t.Run("search issues is pr", searchIssueIsPull) | ||||||
| 	t.Run("search issues is closed", searchIssueIsClosed) | 	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 milestone", searchIssueByMilestoneID) | ||||||
| 	t.Run("search issues by label", searchIssueByLabelID) | 	t.Run("search issues by label", searchIssueByLabelID) | ||||||
| 	t.Run("search issues by time", searchIssueByTime) | 	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) { | func searchIssueByMilestoneID(t *testing.T) { | ||||||
| 	tests := []struct { | 	tests := []struct { | ||||||
| 		opts        SearchOptions | 		opts        SearchOptions | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ type IndexerData struct { | |||||||
| 	// Fields used for filtering | 	// Fields used for filtering | ||||||
| 	IsPull             bool               `json:"is_pull"` | 	IsPull             bool               `json:"is_pull"` | ||||||
| 	IsClosed           bool               `json:"is_closed"` | 	IsClosed           bool               `json:"is_closed"` | ||||||
|  | 	IsArchived         bool               `json:"is_archived"` | ||||||
| 	LabelIDs           []int64            `json:"label_ids"` | 	LabelIDs           []int64            `json:"label_ids"` | ||||||
| 	NoLabel            bool               `json:"no_label"` // True if LabelIDs is empty | 	NoLabel            bool               `json:"no_label"` // True if LabelIDs is empty | ||||||
| 	MilestoneID        int64              `json:"milestone_id"` | 	MilestoneID        int64              `json:"milestone_id"` | ||||||
| @@ -81,8 +82,9 @@ type SearchOptions struct { | |||||||
| 	RepoIDs   []int64 // repository IDs which the issues belong to | 	RepoIDs   []int64 // repository IDs which the issues belong to | ||||||
| 	AllPublic bool    // if include all public repositories | 	AllPublic bool    // if include all public repositories | ||||||
|  |  | ||||||
| 	IsPull   optional.Option[bool] // if the issues is a pull request | 	IsPull     optional.Option[bool] // if the issues is a pull request | ||||||
| 	IsClosed optional.Option[bool] // if the issues is closed | 	IsClosed   optional.Option[bool] // if the issues is closed | ||||||
|  | 	IsArchived optional.Option[bool] // if the repo is archived | ||||||
|  |  | ||||||
| 	IncludedLabelIDs    []int64 // labels the issues have | 	IncludedLabelIDs    []int64 // labels the issues have | ||||||
| 	ExcludedLabelIDs    []int64 // labels the issues don't have | 	ExcludedLabelIDs    []int64 // labels the issues don't have | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	issueIndexerLatestVersion = 3 | 	issueIndexerLatestVersion = 4 | ||||||
|  |  | ||||||
| 	// TODO: make this configurable if necessary | 	// TODO: make this configurable if necessary | ||||||
| 	maxTotalHits = 10000 | 	maxTotalHits = 10000 | ||||||
| @@ -61,6 +61,7 @@ func NewIndexer(url, apiKey, indexerName string) *Indexer { | |||||||
| 			"is_public", | 			"is_public", | ||||||
| 			"is_pull", | 			"is_pull", | ||||||
| 			"is_closed", | 			"is_closed", | ||||||
|  | 			"is_archived", | ||||||
| 			"label_ids", | 			"label_ids", | ||||||
| 			"no_label", | 			"no_label", | ||||||
| 			"milestone_id", | 			"milestone_id", | ||||||
| @@ -145,6 +146,9 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) ( | |||||||
| 	if options.IsClosed.Has() { | 	if options.IsClosed.Has() { | ||||||
| 		query.And(inner_meilisearch.NewFilterEq("is_closed", options.IsClosed.Value())) | 		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 { | 	if options.NoLabelOnly { | ||||||
| 		query.And(inner_meilisearch.NewFilterEq("no_label", true)) | 		query.And(inner_meilisearch.NewFilterEq("no_label", true)) | ||||||
|   | |||||||
| @@ -101,6 +101,7 @@ func getIssueIndexerData(ctx context.Context, issueID int64) (*internal.IndexerD | |||||||
| 		Comments:           comments, | 		Comments:           comments, | ||||||
| 		IsPull:             issue.IsPull, | 		IsPull:             issue.IsPull, | ||||||
| 		IsClosed:           issue.IsClosed, | 		IsClosed:           issue.IsClosed, | ||||||
|  | 		IsArchived:         issue.Repo.IsArchived, | ||||||
| 		LabelIDs:           labels, | 		LabelIDs:           labels, | ||||||
| 		NoLabel:            len(labels) == 0, | 		NoLabel:            len(labels) == 0, | ||||||
| 		MilestoneID:        issue.MilestoneID, | 		MilestoneID:        issue.MilestoneID, | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/base" | 	"code.gitea.io/gitea/modules/base" | ||||||
| 	"code.gitea.io/gitea/modules/git" | 	"code.gitea.io/gitea/modules/git" | ||||||
| 	"code.gitea.io/gitea/modules/indexer/code" | 	"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/indexer/stats" | ||||||
| 	"code.gitea.io/gitea/modules/lfs" | 	"code.gitea.io/gitea/modules/lfs" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"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) | 			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")) | 		ctx.Flash.Success(ctx.Tr("repo.settings.archive.success")) | ||||||
|  |  | ||||||
| 		log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) | 		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")) | 		ctx.Flash.Success(ctx.Tr("repo.settings.unarchive.success")) | ||||||
|  |  | ||||||
| 		log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) | 		log.Trace("Repository was un-archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user