diff --git a/ee/elastic/docs/20240130154724_add_fields_to_projects_index.yml b/ee/elastic/docs/20240130154724_add_fields_to_projects_index.yml new file mode 100644 index 0000000000000000000000000000000000000000..4b4f9ed96784dedcbc42d2fa5bda3b92cd10b262 --- /dev/null +++ b/ee/elastic/docs/20240130154724_add_fields_to_projects_index.yml @@ -0,0 +1,10 @@ +--- +name: AddFieldsToProjectsIndex +version: '20240130154724' +description: 'Adds repository_languages, forked, owner_id and mirror fields to the projects index' +group: group::global search +milestone: '16.9' +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/143771 +obsolete: false +marked_obsolete_by_url: +marked_obsolete_in_milestone: diff --git a/ee/elastic/migrate/20240130154724_add_fields_to_projects_index.rb b/ee/elastic/migrate/20240130154724_add_fields_to_projects_index.rb new file mode 100644 index 0000000000000000000000000000000000000000..868547981795f0ff286f9544f03cbb87b0b318cc --- /dev/null +++ b/ee/elastic/migrate/20240130154724_add_fields_to_projects_index.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class AddFieldsToProjectsIndex < Elastic::Migration + include Elastic::MigrationUpdateMappingsHelper + + DOCUMENT_TYPE = Project + + private + + def new_mappings + { + mirror: { + type: 'boolean' + }, + owner_id: { + type: 'integer' + }, + forked: { + type: 'boolean' + }, + repository_languages: { + type: 'keyword' + } + } + end +end diff --git a/ee/lib/elastic/latest/project_class_proxy.rb b/ee/lib/elastic/latest/project_class_proxy.rb index e16e0c3c5625f99286846c1c1d25788ef30fa4ec..5b9bc5e042d4a00172801de5b5ba991b78a3542e 100644 --- a/ee/lib/elastic/latest/project_class_proxy.rb +++ b/ee/lib/elastic/latest/project_class_proxy.rb @@ -98,7 +98,7 @@ def rejected_project_filter(namespace, options) # rubocop: disable CodeReuse/ActiveRecord def preload_indexing_data(relation) - relation.includes(:project_feature, :route, :namespace, :catalog_resource) + relation.includes(:project_feature, :route, :catalog_resource, :fork_network, :mirror_user, :repository_languages, :group, namespace: :owner) end # rubocop: enable CodeReuse/ActiveRecord end diff --git a/ee/lib/elastic/latest/project_config.rb b/ee/lib/elastic/latest/project_config.rb index f0dde5689193bdb8be1a3974807213449cc83c16..a7e0a4072ea7dd665a08f8cdad6aec0cc2c90797 100644 --- a/ee/lib/elastic/latest/project_config.rb +++ b/ee/lib/elastic/latest/project_config.rb @@ -37,6 +37,11 @@ module ProjectConfig indexes :ci_catalog, type: :boolean indexes :readme_content, type: :text + + indexes :mirror, type: :boolean + indexes :forked, type: :boolean + indexes :owner_id, type: :integer + indexes :repository_languages, type: :keyword end end end diff --git a/ee/lib/elastic/latest/project_instance_proxy.rb b/ee/lib/elastic/latest/project_instance_proxy.rb index 7d3e4121ebfe4fef10bb80354afa15934852efa0..9b75292a0d8b48b11d6c051edae9d9249c74b97f 100644 --- a/ee/lib/elastic/latest/project_instance_proxy.rb +++ b/ee/lib/elastic/latest/project_instance_proxy.rb @@ -38,7 +38,7 @@ def as_indexed_json(_options = {}) # Schema version. The format is Date.today.strftime('%y_%m') # Please update if you're changing the schema of the document - data['schema_version'] = 23_06 + data['schema_version'] = 24_02 data['traversal_ids'] = target.elastic_namespace_ancestry @@ -46,6 +46,13 @@ def as_indexed_json(_options = {}) data['ci_catalog'] = target.catalog_resource.present? end + if ::Elastic::DataMigrationService.migration_has_finished?(:add_fields_to_projects_index) + data['mirror'] = target.mirror? + data['forked'] = target.forked? || false + data['owner_id'] = target.owner.id + data['repository_languages'] = target.repository_languages.map(&:name) + end + unless ::Elastic::DataMigrationService.migration_has_finished?(:migrate_projects_to_separate_index) # Set it as a parent in our `project => child` JOIN field data['join_field'] = es_type diff --git a/ee/spec/elastic/migrate/20240130154724_add_fields_to_projects_index_spec.rb b/ee/spec/elastic/migrate/20240130154724_add_fields_to_projects_index_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..137e4acec5056fda8e9f9efd8a78d14d6676c2a5 --- /dev/null +++ b/ee/spec/elastic/migrate/20240130154724_add_fields_to_projects_index_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_relative 'migration_shared_examples' +require File.expand_path('ee/elastic/migrate/20240130154724_add_fields_to_projects_index.rb') + +RSpec.describe AddFieldsToProjectsIndex, :elastic, feature_category: :global_search do + let(:version) { 20240130154724 } + + include_examples 'migration adds mapping' +end diff --git a/ee/spec/lib/ee/gitlab/elastic/helper_spec.rb b/ee/spec/lib/ee/gitlab/elastic/helper_spec.rb index 4245a15931a472efcbf267037b5519cf7d869c27..37a825c787e387fee68484237334776d4e62447e 100644 --- a/ee/spec/lib/ee/gitlab/elastic/helper_spec.rb +++ b/ee/spec/lib/ee/gitlab/elastic/helper_spec.rb @@ -518,7 +518,8 @@ assignee_id: :all, hashed_root_namespace_id: :all, work_item_type_id: :all, - noteable_id: :all + noteable_id: :all, + owner_id: :all } end diff --git a/ee/spec/lib/elastic/latest/project_instance_proxy_spec.rb b/ee/spec/lib/elastic/latest/project_instance_proxy_spec.rb index 5c680e319ef108142772920c61ac82e2ad041f9d..08d177248b22ecbbc310b6be748467cd3c2f03f9 100644 --- a/ee/spec/lib/elastic/latest/project_instance_proxy_spec.rb +++ b/ee/spec/lib/elastic/latest/project_instance_proxy_spec.rb @@ -5,7 +5,7 @@ RSpec.describe Elastic::Latest::ProjectInstanceProxy, :elastic_helpers, feature_category: :global_search do let_it_be(:project) { create(:project) } - let(:schema_version) { 2306 } + let(:schema_version) { 2402 } subject(:proxy) { described_class.new(project) } @@ -85,6 +85,43 @@ ci_catalog: project.catalog_resource.present? ) end + end + end + + describe 'when add_fields_to_projects_index migration is completed' do + before do + stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true) + set_elasticsearch_migration_to(:add_fields_to_projects_index, including: true) + ensure_elasticsearch_index! # ensure objects are indexed + end + + describe '#as_indexed_json' do + it 'serializes project as hash' do + result = proxy.as_indexed_json.with_indifferent_access + + expect(result).to include( + id: project.id, + name: project.name, + path: project.path, + description: project.description, + namespace_id: project.namespace_id, + created_at: project.created_at, + updated_at: project.updated_at, + archived: project.archived, + last_activity_at: project.last_activity_at, + name_with_namespace: project.name_with_namespace, + path_with_namespace: project.path_with_namespace, + traversal_ids: project.elastic_namespace_ancestry, + type: 'project', + visibility_level: project.visibility_level, + schema_version: schema_version, + ci_catalog: project.catalog_resource.present?, + mirror: project.mirror?, + forked: project.forked? || false, + owner_id: project.owner.id, + repository_languages: project.repository_languages.map(&:name) + ) + end it 'contains the expected mappings' do result = proxy.as_indexed_json.with_indifferent_access.keys diff --git a/ee/spec/models/concerns/elastic/project_spec.rb b/ee/spec/models/concerns/elastic/project_spec.rb index 32a580656a2f4ea2e14e4d42e5e89f81bf14efa4..1410ff4b3df438738d5b2b8347fa837d39476efa 100644 --- a/ee/spec/models/concerns/elastic/project_spec.rb +++ b/ee/spec/models/concerns/elastic/project_spec.rb @@ -7,7 +7,7 @@ stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true) end - let(:schema_version) { 2306 } + let(:schema_version) { 2402 } context 'when limited indexing is on' do let_it_be(:project) { create(:project, :empty_repo, name: 'main_project') } diff --git a/ee/spec/services/elastic/process_bookkeeping_service_spec.rb b/ee/spec/services/elastic/process_bookkeeping_service_spec.rb index 57f2e76d97e0db2e1aee0e556f0ea065aa38a832..e909069a658ba4caaa28bf15a58e9d747598480b 100644 --- a/ee/spec/services/elastic/process_bookkeeping_service_spec.rb +++ b/ee/spec/services/elastic/process_bookkeeping_service_spec.rb @@ -6,6 +6,7 @@ :clean_gitlab_redis_shared_state, :elastic, feature_category: :global_search do + include ProjectForksHelper let(:ref_class) { ::Gitlab::Elastic::DocumentReference } let(:fake_refs) { Array.new(10) { |i| ref_class.new(Issue, i, "issue_#{i}", 'project_1') } } @@ -403,13 +404,18 @@ context 'N+1 queries' do it 'does not have N+1 queries for projects' do - projects = create_list(:project, 2) + project = create(:project) + projects = [create(:project, group: create(:group))] + projects << fork_project(project) + projects << create(:project, :mirror) described_class.track!(*projects) control = ActiveRecord::QueryRecorder.new(skip_cached: false) { described_class.new.execute } - projects += create_list(:project, 3) + projects << create(:project, group: create(:group)) + projects << fork_project(project) + projects << create(:project, :mirror) described_class.track!(*projects)