Skip to content
Snippets Groups Projects
Commit 2540beec authored by Dmitry Gruzd's avatar Dmitry Gruzd :two:
Browse files

Merge branch '342648-add-language-filter-support-for-blob-search' into 'master'

Support language filter for blob searches

See merge request !88674
parents 39ddc2fb 7829b6c8
No related branches found
No related tags found
1 merge request!88674Support language filter for blob searches
Pipeline #577900235 passed
# frozen_string_literal: true
module SearchHelper
# params which should persist when a new tab is selected
SEARCH_GENERIC_PARAMS = [
:search,
:scope,
......@@ -129,7 +130,7 @@ def search_blob_title(project, path)
end
def search_service
@search_service ||= ::SearchService.new(current_user, params.merge(confidential: Gitlab::Utils.to_boolean(params[:confidential])))
@search_service ||= ::SearchService.new(current_user, sanitized_search_params)
end
def search_sort_options
......@@ -481,6 +482,13 @@ def issuable_state_text(issuable)
def feature_flag_tab_enabled?(flag)
@group || Feature.enabled?(flag, current_user, type: :ops)
end
def sanitized_search_params
sanitized_params = params.dup
sanitized_params[:confidential] = Gitlab::Utils.to_boolean(sanitized_params[:confidential]) if sanitized_params.key?(:confidential)
sanitized_params
end
end
SearchHelper.prepend_mod_with('SearchHelper')
......@@ -18,7 +18,7 @@ def execute
public_and_internal_projects: elastic_global,
order_by: params[:order_by],
sort: params[:sort],
filters: { confidential: params[:confidential], state: params[:state] }
filters: { confidential: params[:confidential], state: params[:state], language: params[:language] }
)
end
......
......@@ -32,7 +32,7 @@ def execute
public_and_internal_projects: elastic_global,
order_by: params[:order_by],
sort: params[:sort],
filters: { confidential: params[:confidential], state: params[:state] }
filters: { confidential: params[:confidential], state: params[:state], language: params[:language] }
)
end
......
......@@ -13,26 +13,31 @@ def execute
return super if project.respond_to?(:archived?) && project.archived?
return super unless use_elasticsearch? && use_default_branch?
search = params[:search]
order_by = params[:order_by]
sort = params[:sort]
filters = { confidential: params[:confidential], state: params[:state], language: params[:language] }
if project.is_a?(Array)
project_ids = Array(project).map(&:id)
::Gitlab::Elastic::SearchResults.new(
current_user,
params[:search],
search,
project_ids,
public_and_internal_projects: false,
order_by: params[:order_by],
sort: params[:sort],
filters: { confidential: params[:confidential], state: params[:state] }
order_by: order_by,
sort: sort,
filters: filters
)
else
::Gitlab::Elastic::ProjectSearchResults.new(
current_user,
params[:search],
search,
project: project,
repository_ref: repository_ref,
order_by: params[:order_by],
sort: params[:sort],
filters: { confidential: params[:confidential], state: params[:state] }
order_by: order_by,
sort: sort,
filters: filters
)
end
end
......
......@@ -57,7 +57,7 @@ def options_filter_context(type, options)
}
end
if languages.any?
if type == :blob && languages.any? && allow_aggregations?(type.to_s, options[:count_only], options[:current_user])
filters << {
terms: {
_name: context.name(type, :match, :languages),
......@@ -215,7 +215,7 @@ def search_blob(query, type: 'blob', page: 1, per: 20, options: {})
}
end
if include_aggregations?(type, options[:count_only], options[:current_user])
if allow_aggregations?(type, options[:count_only], options[:current_user])
query_hash[:aggs] = {
language: {
composite: {
......@@ -320,7 +320,7 @@ def apply_simple_query_string(name:, fields:, query:, bool_expr:, count_only:)
end
end
def include_aggregations?(type, count_only, current_user)
def allow_aggregations?(type, count_only, current_user)
type == 'blob' && !count_only && ::Feature.enabled?(:search_blobs_language_aggregation, current_user)
end
end
......
......@@ -26,7 +26,7 @@ def blobs(page: 1, per_page: DEFAULT_PER_PAGE, count_only: false, preload_method
query,
page: (page || 1).to_i,
per: per_page,
options: base_options.merge(count_only: count_only),
options: base_options.merge(count_only: count_only).merge(filters.slice(:language)),
preload_method: preload_method
)
end
......
......@@ -308,7 +308,7 @@ def blobs(page: 1, per_page: DEFAULT_PER_PAGE, count_only: false, preload_method
query,
page: (page || 1).to_i,
per: per_page,
options: base_options.merge(count_only: count_only),
options: base_options.merge(count_only: count_only).merge(filters.slice(:language)),
preload_method: preload_method
)
end
......
......@@ -10,7 +10,7 @@
let(:filters) { {} }
let(:query) { '*' }
subject(:results) { described_class.new(user, query, Project.all.pluck_primary_key, group: group, filters: filters) }
subject(:results) { described_class.new(user, query, group.projects.pluck_primary_key, group: group, filters: filters) }
before do
stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true)
......@@ -50,6 +50,12 @@
end
end
context 'blobs' do
let!(:project) { create(:project, :public, :repository, group: group) }
it_behaves_like 'search results filtered by language'
end
context 'query performance' do
include_examples 'does not hit Elasticsearch twice for objects and counts', %w[projects notes blobs wiki_blobs commits issues merge_requests milestones]
include_examples 'does not load results for count only queries', %w[projects notes blobs wiki_blobs commits issues merge_requests milestones]
......
......@@ -70,7 +70,7 @@
end
context 'filtering' do
let!(:project) { create(:project, :public) }
let!(:project) { create(:project, :public, :repository) }
let(:query) { 'foo' }
context 'issues' do
......@@ -100,6 +100,10 @@
include_examples 'search results filtered by state'
end
context 'blobs' do
it_behaves_like 'search results filtered by language'
end
end
end
......
......@@ -770,7 +770,7 @@
end
end
describe 'project scoping' do
describe 'projects' do
it "returns items for project" do
project = create :project, :repository, name: "term"
project.add_developer(user)
......@@ -1014,6 +1014,13 @@ def self.ruby_method_123(ruby_another_method_arg)
expect(search_for('ruby_call_method_123')).to include(file_name)
end
end
context 'filtering' do
let(:project) { project_1 }
let(:results) { described_class.new(user, query, [project.id], filters: filters) }
it_behaves_like 'search results filtered by language'
end
end
describe 'wikis', :sidekiq_inline do
......
# frozen_string_literal: true
RSpec.shared_examples 'search results filtered by language' do
let(:scope) { 'blobs' }
let(:filters) { { language: %w[Ruby Markdown] } }
let(:query) { 'def | popen | test' }
before do
project.repository.index_commits_and_blobs
ensure_elasticsearch_index!
end
subject(:blob_results) { results.objects('blobs') }
it 'filters by language', :sidekiq_inline, :aggregate_failures do
expected_paths = %w[
files/ruby/popen.rb
files/markdown/ruby-style-guide.md
files/ruby/regex.rb
files/ruby/version_info.rb
CONTRIBUTING.md
]
paths = blob_results.map { |blob| blob.binary_path }
expect(blob_results.size).to eq(5)
expect(paths).to match_array(expected_paths)
end
context 'when the search_blobs_language_aggregation feature flag is disabled' do
before do
stub_feature_flags(search_blobs_language_aggregation: false)
end
it 'does not filter by language', :sidekiq_inline, :aggregate_failures do
expected_paths = %w[
CHANGELOG
CONTRIBUTING.md
bar/branch-test.txt
custom-highlighting/test.gitlab-custom
files/ruby/popen.rb
files/ruby/regex.rb
files/ruby/version_info.rb
files/whitespace
encoding/test.txt
files/markdown/ruby-style-guide.md
]
paths = blob_results.map { |blob| blob.binary_path }
expect(blob_results.size).to eq(10)
expect(paths).to match_array(expected_paths)
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment