From c64de404c8cc3f8f468b62c3db5d7f43766cb433 Mon Sep 17 00:00:00 2001 From: maddievn Date: Mon, 29 May 2023 12:33:11 +0200 Subject: [PATCH 1/4] Don't include archived projects by default Archived projects can be included by specifying incluce_archived=true in params Changelog: changed --- app/helpers/search_helper.rb | 9 ++- app/services/concerns/search/filter.rb | 2 +- app/services/search/global_service.rb | 2 +- ee/lib/elastic/latest/project_class_proxy.rb | 6 +- ee/lib/gitlab/elastic/search_results.rb | 2 + .../latest/project_class_proxy_spec.rb | 61 +++++++++++++++++++ .../elastic/group_search_results_spec.rb | 13 ++++ .../lib/gitlab/elastic/search_results_spec.rb | 14 +++++ lib/gitlab/search_results.rb | 4 +- spec/controllers/search_controller_spec.rb | 2 + spec/helpers/search_helper_spec.rb | 28 +++++++-- spec/lib/gitlab/group_search_results_spec.rb | 15 ++++- spec/lib/gitlab/search_results_spec.rb | 15 ++++- spec/services/search/global_service_spec.rb | 21 ++++--- .../search_archived_filter_shared_examples.rb | 30 +++++++++ 15 files changed, 201 insertions(+), 23 deletions(-) create mode 100644 ee/spec/lib/elastic/latest/project_class_proxy_spec.rb create mode 100644 spec/support/shared_examples/lib/gitlab/search_archived_filter_shared_examples.rb diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 2187126272d9db..04ab6fe6afb80f 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -608,7 +608,14 @@ def feature_flag_tab_enabled?(flag) def sanitized_search_params sanitized_params = params.dup - sanitized_params[:confidential] = Gitlab::Utils.to_boolean(sanitized_params[:confidential]) if sanitized_params.key?(:confidential) + + if sanitized_params.key?(:confidential) + sanitized_params[:confidential] = Gitlab::Utils.to_boolean(sanitized_params[:confidential]) + end + + if sanitized_params.key?(:include_archived) + sanitized_params[:include_archived] = Gitlab::Utils.to_boolean(sanitized_params[:include_archived]) + end sanitized_params end diff --git a/app/services/concerns/search/filter.rb b/app/services/concerns/search/filter.rb index c358f49eef1518..e234edcfce435b 100644 --- a/app/services/concerns/search/filter.rb +++ b/app/services/concerns/search/filter.rb @@ -5,7 +5,7 @@ module Filter private def filters - { state: params[:state], confidential: params[:confidential] } + { state: params[:state], confidential: params[:confidential], include_archived: params[:include_archived] } end end end diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb index 2d4952dacfd485..85ca0b850f5ba9 100644 --- a/app/services/search/global_service.rb +++ b/app/services/search/global_service.rb @@ -25,7 +25,7 @@ def execute # rubocop: disable CodeReuse/ActiveRecord def projects - @projects ||= ProjectsFinder.new(params: { non_archived: true }, current_user: current_user).execute.preload(:topics, :project_topics) + @projects ||= ProjectsFinder.new(current_user: current_user).execute.preload(:topics, :project_topics) end def allowed_scopes diff --git a/ee/lib/elastic/latest/project_class_proxy.rb b/ee/lib/elastic/latest/project_class_proxy.rb index b22cb80243d4f6..98071b96f2e496 100644 --- a/ee/lib/elastic/latest/project_class_proxy.rb +++ b/ee/lib/elastic/latest/project_class_proxy.rb @@ -20,11 +20,11 @@ def elastic_search(query, options: {}) } end - if options[:non_archived] + unless options[:include_archived] filters << { terms: { - _name: context.name(:not_archived), - archived: [!options[:non_archived]].flatten + _name: context.name(:archived, false), + archived: [false] } } end diff --git a/ee/lib/gitlab/elastic/search_results.rb b/ee/lib/gitlab/elastic/search_results.rb index a2238606e64866..17614606c964d6 100644 --- a/ee/lib/gitlab/elastic/search_results.rb +++ b/ee/lib/gitlab/elastic/search_results.rb @@ -269,6 +269,8 @@ def base_options def scope_options(scope) case scope + when :projects + base_options.merge(filters.slice(:include_archived)) when :merge_requests base_options.merge(filters.slice(:order_by, :sort, :state)) when :issues diff --git a/ee/spec/lib/elastic/latest/project_class_proxy_spec.rb b/ee/spec/lib/elastic/latest/project_class_proxy_spec.rb new file mode 100644 index 00000000000000..360fa85043224f --- /dev/null +++ b/ee/spec/lib/elastic/latest/project_class_proxy_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Elastic::Latest::ProjectClassProxy, feature_category: :global_search do + subject { described_class.new(Project) } + + let(:query) { 'blob' } + let(:options) { {} } + let(:elastic_search) { subject.elastic_search(query, options: options) } + let(:request) { Elasticsearch::Model::Searching::SearchRequest.new(Project, '*') } + let(:response) do + Elasticsearch::Model::Response::Response.new(Project, request) + end + + before do + stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true) + end + + describe '#elastic_search' do + describe 'query', :elastic_delete_by_query do + it 'has the correct named queries' do + elastic_search.response + + assert_named_queries( + 'project:match:search_terms', + 'doc:is_a:project', + 'project:archived:false' + ) + end + + context 'when project_ids is set' do + let(:options) { { project_ids: [create(:project).id] } } + + it 'has the correct named queries' do + elastic_search.response + + assert_named_queries( + 'project:match:search_terms', + 'doc:is_a:project', + 'project:membership:id', + 'project:archived:false' + ) + end + end + + context 'when include_archived is set' do + let(:options) { { include_archived: true } } + + it 'does not have a filter for archived' do + elastic_search.response + + assert_named_queries( + 'project:match:search_terms', + 'doc:is_a:project' + ) + end + end + end + end +end diff --git a/ee/spec/lib/gitlab/elastic/group_search_results_spec.rb b/ee/spec/lib/gitlab/elastic/group_search_results_spec.rb index 63458350197a94..548b3153682702 100644 --- a/ee/spec/lib/gitlab/elastic/group_search_results_spec.rb +++ b/ee/spec/lib/gitlab/elastic/group_search_results_spec.rb @@ -57,6 +57,19 @@ it_behaves_like 'search results filtered by language' end + context 'for projects' do + let!(:unarchived_project) { create(:project, :public, group: group) } + let!(:archived_project) { create(:project, :archived, :public, group: group) } + + let(:scope) { 'projects' } + + it_behaves_like 'search results filtered by archived' do + before do + ensure_elasticsearch_index! + end + end + end + describe 'users' do let(:query) { 'john' } let(:scope) { 'users' } diff --git a/ee/spec/lib/gitlab/elastic/search_results_spec.rb b/ee/spec/lib/gitlab/elastic/search_results_spec.rb index 57dec8386064bc..2df30b673b1492 100644 --- a/ee/spec/lib/gitlab/elastic/search_results_spec.rb +++ b/ee/spec/lib/gitlab/elastic/search_results_spec.rb @@ -373,6 +373,20 @@ include_examples 'search results filtered by state' include_examples 'search results filtered by confidential' include_examples 'search results filtered by labels' + + context 'for projects' do + let_it_be(:group) { create(:group) } + let!(:unarchived_project) { create(:project, :public, group: group) } + let!(:archived_project) { create(:project, :archived, :public, group: group) } + + let(:results) { described_class.new(user, '*', [unarchived_project.id, archived_project.id], filters: filters) } + + it_behaves_like 'search results filtered by archived' do + before do + ensure_elasticsearch_index! + end + end + end end context 'ordering' do diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb index 93befc2df57458..5d2dc2f7d1942e 100644 --- a/lib/gitlab/search_results.rb +++ b/lib/gitlab/search_results.rb @@ -174,7 +174,9 @@ def apply_sort(results, scope: nil) # rubocop: enable CodeReuse/ActiveRecord def projects - limit_projects.search(query) + scope = limit_projects + scope = filters[:include_archived] ? scope : scope.non_archived + scope.search(query) end def issues(finder_params = {}) diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index 497e2d84f4fcde..0d357eae6c09c7 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -543,6 +543,7 @@ def request expect(payload[:metadata]['meta.search.scope']).to eq('issues') expect(payload[:metadata]['meta.search.force_search_results']).to eq('true') expect(payload[:metadata]['meta.search.filters.confidential']).to eq('true') + expect(payload[:metadata]['meta.search.filters.include_archived']).to eq('true') expect(payload[:metadata]['meta.search.filters.state']).to eq('true') expect(payload[:metadata]['meta.search.project_ids']).to eq(%w(456 789)) expect(payload[:metadata]['meta.search.type']).to eq('basic') @@ -557,6 +558,7 @@ def request project_id: '456', project_ids: %w(456 789), confidential: true, + include_archived: true, state: true, force_search_results: true, language: 'ruby' diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index 2cea577a852d78..807733b13bb207 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -711,22 +711,38 @@ def simple_sanitize(str) allow(self).to receive(:current_user).and_return(:the_current_user) end - where(:confidential, :expected) do + where(:input, :expected) do '0' | false '1' | true 'yes' | true 'no' | false + 'true' | true + 'false' | false true | true false | false end - let(:params) { { confidential: confidential } } + describe 'for confidential' do + let(:params) { { confidential: input } } - with_them do - it 'transforms confidentiality param' do - expect(::SearchService).to receive(:new).with(:the_current_user, { confidential: expected }) + with_them do + it 'transforms param' do + expect(::SearchService).to receive(:new).with(:the_current_user, { confidential: expected }) - subject + subject + end + end + end + + describe 'for include_archived' do + let(:params) { { include_archived: input } } + + with_them do + it 'transforms param' do + expect(::SearchService).to receive(:new).with(:the_current_user, { include_archived: expected }) + + subject + end end end end diff --git a/spec/lib/gitlab/group_search_results_spec.rb b/spec/lib/gitlab/group_search_results_spec.rb index ec96a069b8fff1..1206a1c913194d 100644 --- a/spec/lib/gitlab/group_search_results_spec.rb +++ b/spec/lib/gitlab/group_search_results_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::GroupSearchResults do +RSpec.describe Gitlab::GroupSearchResults, feature_category: :global_search do # group creation calls GroupFinder, so need to create the group # before so expect(GroupsFinder) check works let_it_be(:group) { create(:group) } @@ -46,6 +46,19 @@ include_examples 'search results filtered by state' end + describe '#projects' do + let(:scope) { 'projects' } + let(:query) { 'Test' } + + describe 'filtering' do + let_it_be(:group) { create(:group) } + let_it_be(:unarchived_project) { create(:project, :public, group: group, name: 'Test1') } + let_it_be(:archived_project) { create(:project, :archived, :public, group: group, name: 'Test2') } + + it_behaves_like 'search results filtered by archived' + end + end + describe 'user search' do subject(:objects) { results.objects('users') } diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb index a38073e7c513e2..18b42da659b51c 100644 --- a/spec/lib/gitlab/search_results_spec.rb +++ b/spec/lib/gitlab/search_results_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::SearchResults do +RSpec.describe Gitlab::SearchResults, feature_category: :global_search do include ProjectForksHelper include SearchHelpers using RSpec::Parameterized::TableSyntax @@ -260,6 +260,19 @@ end end + describe '#projects' do + let(:scope) { 'projects' } + let(:query) { 'Test' } + + describe 'filtering' do + let_it_be(:group) { create(:group) } + let_it_be(:unarchived_project) { create(:project, :public, group: group, name: 'Test1') } + let_it_be(:archived_project) { create(:project, :archived, :public, group: group, name: 'Test2') } + + it_behaves_like 'search results filtered by archived' + end + end + describe '#users' do it 'does not call the UsersFinder when the current_user is not allowed to read users list' do allow(Ability).to receive(:allowed?).and_return(false) diff --git a/spec/services/search/global_service_spec.rb b/spec/services/search/global_service_spec.rb index 6250d32574f8a0..f77d81851e3cc8 100644 --- a/spec/services/search/global_service_spec.rb +++ b/spec/services/search/global_service_spec.rb @@ -3,13 +3,14 @@ require 'spec_helper' RSpec.describe Search::GlobalService, feature_category: :global_search do - let(:user) { create(:user) } - let(:internal_user) { create(:user) } + let_it_be(:user) { create(:user) } + let_it_be(:internal_user) { create(:user) } - let!(:found_project) { create(:project, :private, name: 'searchable_project') } - let!(:unfound_project) { create(:project, :private, name: 'unfound_project') } - let!(:internal_project) { create(:project, :internal, name: 'searchable_internal_project') } - let!(:public_project) { create(:project, :public, name: 'searchable_public_project') } + let_it_be(:found_project) { create(:project, :private, name: 'searchable_project') } + let_it_be(:unfound_project) { create(:project, :private, name: 'unfound_project') } + let_it_be(:internal_project) { create(:project, :internal, name: 'searchable_internal_project') } + let_it_be(:public_project) { create(:project, :public, name: 'searchable_public_project') } + let_it_be(:archived_project) { create(:project, :public, archived: true, name: 'archived_project') } before do found_project.add_maintainer(user) @@ -44,12 +45,16 @@ end it 'does not return archived projects' do - archived_project = create(:project, :public, archived: true, name: 'archived_project') - results = described_class.new(user, search: "archived").execute expect(results.objects('projects')).not_to include(archived_project) end + + it 'returns archived projects if the include_archived option is passed' do + results = described_class.new(user, { include_archived: true, search: "archived" }).execute + + expect(results.objects('projects')).to include(archived_project) + end end end diff --git a/spec/support/shared_examples/lib/gitlab/search_archived_filter_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/search_archived_filter_shared_examples.rb new file mode 100644 index 00000000000000..7bcefd07fc4a78 --- /dev/null +++ b/spec/support/shared_examples/lib/gitlab/search_archived_filter_shared_examples.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'search results filtered by archived' do + context 'when filter not provided (all behavior)' do + let(:filters) { {} } + + it 'returns unarchived results only', :aggregate_failures do + expect(results.objects('projects')).to include unarchived_project + expect(results.objects('projects')).not_to include archived_project + end + end + + context 'when include_archived is true' do + let(:filters) { { include_archived: true } } + + it 'returns archived and unarchived results', :aggregate_failures do + expect(results.objects('projects')).to include unarchived_project + expect(results.objects('projects')).to include archived_project + end + end + + context 'when include_archived filter is false' do + let(:filters) { { include_archived: false } } + + it 'returns unarchived results only', :aggregate_failures do + expect(results.objects('projects')).to include unarchived_project + expect(results.objects('projects')).not_to include archived_project + end + end +end -- GitLab From 8c0ef05386808de571173ea5a99a01da454c91d9 Mon Sep 17 00:00:00 2001 From: maddievn Date: Mon, 29 May 2023 13:27:29 +0200 Subject: [PATCH 2/4] Fix specs --- ee/spec/services/search/project_service_spec.rb | 2 +- spec/controllers/search_controller_spec.rb | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ee/spec/services/search/project_service_spec.rb b/ee/spec/services/search/project_service_spec.rb index 6e8311cd026f19..5be3b14d938c7e 100644 --- a/ee/spec/services/search/project_service_spec.rb +++ b/ee/spec/services/search/project_service_spec.rb @@ -35,7 +35,7 @@ repository_ref: params[:repository_ref], order_by: params[:order_by], sort: params[:sort], - filters: { confidential: nil, state: nil, language: nil, labels: nil } + filters: { confidential: nil, state: nil, language: nil, labels: nil, include_archived: nil } ).and_return search_results expect(search_service.execute).to eq(search_results) diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index 0d357eae6c09c7..6c48962210d62d 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -543,7 +543,6 @@ def request expect(payload[:metadata]['meta.search.scope']).to eq('issues') expect(payload[:metadata]['meta.search.force_search_results']).to eq('true') expect(payload[:metadata]['meta.search.filters.confidential']).to eq('true') - expect(payload[:metadata]['meta.search.filters.include_archived']).to eq('true') expect(payload[:metadata]['meta.search.filters.state']).to eq('true') expect(payload[:metadata]['meta.search.project_ids']).to eq(%w(456 789)) expect(payload[:metadata]['meta.search.type']).to eq('basic') -- GitLab From 53ca6a90f9a06390b95dcfa31f006adcd4829fec Mon Sep 17 00:00:00 2001 From: Madelein van Niekerk Date: Tue, 30 May 2023 07:46:22 +0000 Subject: [PATCH 3/4] Update documentation for archived projects Changelog: changed --- doc/user/search/index.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/user/search/index.md b/doc/user/search/index.md index f6733abd305ad0..19931e7916ae5f 100644 --- a/doc/user/search/index.md +++ b/doc/user/search/index.md @@ -96,8 +96,6 @@ To filter code search results by one or more languages: ## Search for projects by full path > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108906) in GitLab 15.9 [with a flag](../../administration/feature_flags.md) named `full_path_project_search`. Disabled by default. -> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/388473) on GitLab.com in GitLab 15.9. -> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111808) on self-managed GitLab 15.10. > - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114932) in GitLab 15.11. Feature flag `full_path_project_search` removed. You can search for a project by entering its full path (including the namespace it belongs to) in the search box. @@ -108,6 +106,12 @@ For example, the search query: - `gitlab-org/gitlab` searches for the `gitlab` project in the `gitlab-org` namespace. - `gitlab-org/` displays autocomplete suggestions for projects that belong to the `gitlab-org` namespace. +### Search archived projects + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121981) in GitLab 16.0. + +By default, archived projects are excluded from the search results. To include archived projects, add the parameter `include_archived=true` to the URL. + ## Search for a SHA You can search for a commit SHA. -- GitLab From 92d2df4bdbd844ea58e6011a50730706ccd5d1c7 Mon Sep 17 00:00:00 2001 From: Dmitry Gruzd Date: Wed, 31 May 2023 13:39:43 +0000 Subject: [PATCH 4/4] Apply 1 suggestion(s) to 1 file(s) --- doc/user/search/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/search/index.md b/doc/user/search/index.md index 19931e7916ae5f..24bc31a103f628 100644 --- a/doc/user/search/index.md +++ b/doc/user/search/index.md @@ -108,7 +108,7 @@ For example, the search query: ### Search archived projects -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121981) in GitLab 16.0. +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121981) in GitLab 16.1. By default, archived projects are excluded from the search results. To include archived projects, add the parameter `include_archived=true` to the URL. -- GitLab