From bfaa68d05954f475fd72451dcca0790a952e2e2b Mon Sep 17 00:00:00 2001
From: Michael Becker <11881043-wandering_person@users.noreply.gitlab.com>
Date: Mon, 22 Jan 2024 03:31:19 +0000
Subject: [PATCH] Add `include_archived` param to the
 `Namespaces::ProjectsFinder`

Context
----------

For the group-level view of the Vulnerability Report, we exclude
archived projects.

However, the project filter list includes archived projects as
selections

We want to exclude archived projects from that list.

The list is populated by a graphql
call ([`security_dashboard/graphql/queries/group_projects.query.graphql`][1])

Which ultimately ends up calling this finder in the
[`namespace_projects_resolver`][0].

This Commit
----------

This commit adds a param to the finder to allow us to eventually filter
out archived projects in our graphql query.

As the existing behavior of this finder is to include archived
projects, the default for the new param is `include_archived: true` to
keep any other usages of this finder unaffected.

[0]:https://gitlab.com/gitlab-org/gitlab/-/blob/b1f2a2d85e2f920b1e0a98f71d1d29a9aed3fc5c/app/graphql/resolvers/namespace_projects_resolver.rb
[1]:https://gitlab.com/gitlab-org/gitlab/-/blob/b1f2a2d85e2f920b1e0a98f71d1d29a9aed3fc5c/ee/app/assets/javascripts/security_dashboard/graphql/queries/group_projects.query.graphql#L4

Related to https://gitlab.com/gitlab-org/gitlab/-/issues/426520
---
 app/finders/namespaces/projects_finder.rb     |  8 ++++
 .../namespaces/projects_finder_spec.rb        | 45 +++++++++++++++----
 2 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/app/finders/namespaces/projects_finder.rb b/app/finders/namespaces/projects_finder.rb
index 0194ee4080170..6547d41dcdddd 100644
--- a/app/finders/namespaces/projects_finder.rb
+++ b/app/finders/namespaces/projects_finder.rb
@@ -11,6 +11,7 @@
 #     sort: string
 #     search: string
 #     include_subgroups: boolean
+#     include_archived: boolean
 #     ids: int[]
 #     with_issues_enabled: boolean
 #     with_merge_requests_enabled: boolean
@@ -45,6 +46,7 @@ def execute
 
     def filter_projects(collection)
       collection = by_ids(collection)
+      collection = by_archived(collection)
       collection = by_similarity(collection)
       by_feature_availability(collection)
     end
@@ -55,6 +57,12 @@ def by_ids(items)
       items.id_in(params[:ids])
     end
 
+    def by_archived(items)
+      return items if Gitlab::Utils.to_boolean(params[:include_archived], default: true)
+
+      items.non_archived
+    end
+
     def by_similarity(items)
       return items unless params[:search].present?
 
diff --git a/spec/finders/namespaces/projects_finder_spec.rb b/spec/finders/namespaces/projects_finder_spec.rb
index 9291572d8d135..10d8145d15ac2 100644
--- a/spec/finders/namespaces/projects_finder_spec.rb
+++ b/spec/finders/namespaces/projects_finder_spec.rb
@@ -2,7 +2,7 @@
 
 require 'spec_helper'
 
-RSpec.describe Namespaces::ProjectsFinder do
+RSpec.describe Namespaces::ProjectsFinder, feature_category: :groups_and_projects do
   let_it_be(:current_user) { create(:user) }
   let_it_be(:namespace) { create(:group, :public) }
   let_it_be(:subgroup) { create(:group, parent: namespace) }
@@ -12,6 +12,7 @@
   let_it_be(:project_4) { create(:project, :public, :merge_requests_disabled, path: 'test-project-2', group: namespace, name: 'Test Project 2') }
   let_it_be(:project_5) { create(:project, group: subgroup, marked_for_deletion_at: 1.day.ago, pending_delete: true) }
   let_it_be(:project_6) { create(:project, group: namespace, marked_for_deletion_at: 1.day.ago, pending_delete: true) }
+  let_it_be(:project_7) { create(:project, :archived, group: namespace) }
 
   let(:params) { {} }
 
@@ -30,14 +31,14 @@
 
     context 'with a namespace' do
       it 'returns the project for the namespace' do
-        expect(projects).to contain_exactly(project_1, project_2, project_4, project_6)
+        expect(projects).to contain_exactly(project_1, project_2, project_4, project_6, project_7)
       end
 
       context 'when not_aimed_for_deletion is provided' do
         let(:params) { { not_aimed_for_deletion: true } }
 
         it 'returns all projects not aimed for deletion for the namespace' do
-          expect(projects).to contain_exactly(project_1, project_2, project_4)
+          expect(projects).to contain_exactly(project_1, project_2, project_4, project_7)
         end
       end
 
@@ -45,7 +46,7 @@
         let(:params) { { include_subgroups: true } }
 
         it 'returns all projects for the namespace' do
-          expect(projects).to contain_exactly(project_1, project_2, project_3, project_4, project_5, project_6)
+          expect(projects).to contain_exactly(project_1, project_2, project_3, project_4, project_5, project_6, project_7)
         end
 
         context 'when ids are provided' do
@@ -60,7 +61,33 @@
           let(:params) { { not_aimed_for_deletion: true, include_subgroups: true } }
 
           it 'returns all projects not aimed for deletion for the namespace' do
-            expect(projects).to contain_exactly(project_1, project_2, project_3, project_4)
+            expect(projects).to contain_exactly(project_1, project_2, project_3, project_4, project_7)
+          end
+        end
+      end
+
+      context 'for include_archived parameter' do
+        context 'when include_archived is not provided' do
+          let(:params) { {} }
+
+          it 'returns archived and non-archived projects' do
+            expect(projects).to contain_exactly(project_1, project_2, project_4, project_6, project_7)
+          end
+        end
+
+        context 'when include_archived is true' do
+          let(:params) { { include_archived: true } }
+
+          it 'returns archived and non-archived projects' do
+            expect(projects).to contain_exactly(project_1, project_2, project_4, project_6, project_7)
+          end
+        end
+
+        context 'when include_archived is false' do
+          let(:params) { { include_archived: false } }
+
+          it 'returns ONLY non-archived projects' do
+            expect(projects).to contain_exactly(project_1, project_2, project_4, project_6)
           end
         end
       end
@@ -77,7 +104,7 @@
         let(:params) { { with_issues_enabled: true, include_subgroups: true } }
 
         it 'returns the projects that have issues enabled' do
-          expect(projects).to contain_exactly(project_1, project_2, project_4, project_5, project_6)
+          expect(projects).to contain_exactly(project_1, project_2, project_4, project_5, project_6, project_7)
         end
       end
 
@@ -85,7 +112,7 @@
         let(:params) { { with_merge_requests_enabled: true } }
 
         it 'returns the projects that have merge requests enabled' do
-          expect(projects).to contain_exactly(project_1, project_2, project_6)
+          expect(projects).to contain_exactly(project_1, project_2, project_6, project_7)
         end
       end
 
@@ -101,7 +128,7 @@
         let(:params) { { sort: :similarity } }
 
         it 'returns all projects' do
-          expect(projects).to contain_exactly(project_1, project_2, project_4, project_6)
+          expect(projects).to contain_exactly(project_1, project_2, project_4, project_6, project_7)
         end
       end
 
@@ -124,7 +151,7 @@
         end
 
         it 'returns projects sorted by latest activity' do
-          expect(projects).to eq([project_4, project_1, project_2, project_6])
+          expect(projects).to eq([project_4, project_1, project_2, project_6, project_7])
         end
       end
     end
-- 
GitLab