From 803a757db1d05d44a70fcb14a2728647b512556b Mon Sep 17 00:00:00 2001
From: Kasia Misirli <kmisirli@gitlab.com>
Date: Thu, 20 Jul 2023 15:53:49 +0000
Subject: [PATCH] Add openMergeRequestsCount and openIssuesCount to
 CiCatalogResource

---
 app/graphql/types/merge_request_state_enum.rb |  3 +-
 doc/api/graphql/reference/index.md            |  4 +-
 .../graphql/types/ci/catalog/resource_type.rb | 16 ++++
 .../types/ci/catalog/resource_type_spec.rb    |  2 +
 .../api/graphql/ci/catalog/resource_spec.rb   | 93 +++++++++++++++++++
 .../api/graphql/ci/catalog/resources_spec.rb  | 84 +++++++++++++++++
 .../types/merge_request_state_enum_spec.rb    |  2 +-
 7 files changed, 201 insertions(+), 3 deletions(-)

diff --git a/app/graphql/types/merge_request_state_enum.rb b/app/graphql/types/merge_request_state_enum.rb
index bcf18b836de1..e03b79dfeb84 100644
--- a/app/graphql/types/merge_request_state_enum.rb
+++ b/app/graphql/types/merge_request_state_enum.rb
@@ -5,6 +5,7 @@ class MergeRequestStateEnum < IssuableStateEnum
     graphql_name 'MergeRequestState'
     description 'State of a GitLab merge request'
 
-    value 'merged', description: "Merge request has been merged."
+    value 'merged', description: 'Merge request has been merged.'
+    value 'opened', description: 'Opened merge request.'
   end
 end
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 17868bb33a37..3333af965b68 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -13199,6 +13199,8 @@ Represents the total number of issues and their weights for a particular day.
 | <a id="cicatalogresourceid"></a>`id` **{warning-solid}** | [`ID!`](#id) | **Introduced** in 15.11. This feature is an Experiment. It can be changed or removed at any time. ID of the catalog resource. |
 | <a id="cicatalogresourcelatestversion"></a>`latestVersion` **{warning-solid}** | [`Release`](#release) | **Introduced** in 16.1. This feature is an Experiment. It can be changed or removed at any time. Latest version of the catalog resource. |
 | <a id="cicatalogresourcename"></a>`name` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.11. This feature is an Experiment. It can be changed or removed at any time. Name of the catalog resource. |
+| <a id="cicatalogresourceopenissuescount"></a>`openIssuesCount` **{warning-solid}** | [`Int!`](#int) | **Introduced** in 16.3. This feature is an Experiment. It can be changed or removed at any time. Count of open issues that belong to the the catalog resource. |
+| <a id="cicatalogresourceopenmergerequestscount"></a>`openMergeRequestsCount` **{warning-solid}** | [`Int!`](#int) | **Introduced** in 16.3. This feature is an Experiment. It can be changed or removed at any time. Count of open merge requests that belong to the the catalog resource. |
 | <a id="cicatalogresourcereadmehtml"></a>`readmeHtml` **{warning-solid}** | [`String!`](#string) | **Introduced** in 16.1. This feature is an Experiment. It can be changed or removed at any time. GitLab Flavored Markdown rendering of `readme`. |
 | <a id="cicatalogresourcerootnamespace"></a>`rootNamespace` **{warning-solid}** | [`Namespace`](#namespace) | **Introduced** in 16.1. This feature is an Experiment. It can be changed or removed at any time. Root namespace of the catalog resource. |
 | <a id="cicatalogresourcestarcount"></a>`starCount` **{warning-solid}** | [`Int!`](#int) | **Introduced** in 16.1. This feature is an Experiment. It can be changed or removed at any time. Number of times the catalog resource has been starred. |
@@ -26576,7 +26578,7 @@ State of a GitLab merge request.
 | <a id="mergerequeststateclosed"></a>`closed` | In closed state. |
 | <a id="mergerequeststatelocked"></a>`locked` | Discussion has been locked. |
 | <a id="mergerequeststatemerged"></a>`merged` | Merge request has been merged. |
-| <a id="mergerequeststateopened"></a>`opened` | In open state. |
+| <a id="mergerequeststateopened"></a>`opened` | Opened merge request. |
 
 ### `MergeStatus`
 
diff --git a/ee/app/graphql/types/ci/catalog/resource_type.rb b/ee/app/graphql/types/ci/catalog/resource_type.rb
index 773dbf7677d7..99067d4308a9 100644
--- a/ee/app/graphql/types/ci/catalog/resource_type.rb
+++ b/ee/app/graphql/types/ci/catalog/resource_type.rb
@@ -9,6 +9,14 @@ class ResourceType < BaseObject
 
         connection_type_class(Types::CountableConnectionType)
 
+        field :open_issues_count, GraphQL::Types::Int, null: false,
+          description: 'Count of open issues that belong to the the catalog resource.',
+          alpha: { milestone: '16.3' }
+
+        field :open_merge_requests_count, GraphQL::Types::Int, null: false,
+          description: 'Count of open merge requests that belong to the the catalog resource.',
+          alpha: { milestone: '16.3' }
+
         field :id, GraphQL::Types::ID, null: false, description: 'ID of the catalog resource.',
           alpha: { milestone: '15.11' }
 
@@ -48,6 +56,14 @@ class ResourceType < BaseObject
         markdown_field :readme_html, null: false,
           alpha: { milestone: '16.1' }
 
+        def open_issues_count
+          BatchLoader::GraphQL.wrap(object.project.open_issues_count)
+        end
+
+        def open_merge_requests_count
+          BatchLoader::GraphQL.wrap(object.project.open_merge_requests_count)
+        end
+
         def web_path
           ::Gitlab::Routing.url_helpers.project_path(object.project)
         end
diff --git a/ee/spec/graphql/types/ci/catalog/resource_type_spec.rb b/ee/spec/graphql/types/ci/catalog/resource_type_spec.rb
index 85e18cf55c50..7c94fe2213a5 100644
--- a/ee/spec/graphql/types/ci/catalog/resource_type_spec.rb
+++ b/ee/spec/graphql/types/ci/catalog/resource_type_spec.rb
@@ -18,6 +18,8 @@
       forks_count
       root_namespace
       readme_html
+      open_issues_count
+      open_merge_requests_count
     ]
 
     expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/ee/spec/requests/api/graphql/ci/catalog/resource_spec.rb b/ee/spec/requests/api/graphql/ci/catalog/resource_spec.rb
index 4b5cc3c900fb..77110fd02566 100644
--- a/ee/spec/requests/api/graphql/ci/catalog/resource_spec.rb
+++ b/ee/spec/requests/api/graphql/ci/catalog/resource_spec.rb
@@ -259,4 +259,97 @@
       )
     end
   end
+
+  describe 'openIssuesCount' do
+    before do
+      stub_licensed_features(ci_namespace_catalog: true)
+    end
+
+    context 'when open_issue_count is requested' do
+      let(:query) do
+        <<~GQL
+          query {
+            ciCatalogResource(id: "#{resource.to_global_id}") {
+              openIssuesCount
+            }
+          }
+        GQL
+      end
+
+      it 'returns the correct count' do
+        create(:issue, :opened, project: project)
+        create(:issue, :opened, project: project)
+
+        namespace.add_developer(user)
+
+        post_query
+
+        expect(graphql_data_at(:ciCatalogResource)).to match(
+          a_graphql_entity_for(
+            open_issues_count: 2
+          )
+        )
+      end
+
+      context 'when open_issue_count is zero' do
+        it 'returns zero' do
+          namespace.add_developer(user)
+
+          post_query
+
+          expect(graphql_data_at(:ciCatalogResource)).to match(
+            a_graphql_entity_for(
+              open_issues_count: 0
+            )
+          )
+        end
+      end
+    end
+  end
+
+  describe 'openMergeRequestsCount' do
+    before do
+      stub_licensed_features(ci_namespace_catalog: true)
+    end
+
+    context 'when merge_requests_count is requested' do
+      let(:query) do
+        <<~GQL
+          query {
+            ciCatalogResource(id: "#{resource.to_global_id}") {
+              openMergeRequestsCount
+            }
+          }
+        GQL
+      end
+
+      it 'returns the correct count' do
+        create(:merge_request, :opened, source_project: project)
+
+        namespace.add_developer(user)
+
+        post_query
+
+        expect(graphql_data_at(:ciCatalogResource)).to match(
+          a_graphql_entity_for(
+            open_merge_requests_count: 1
+          )
+        )
+      end
+
+      context 'when open merge_requests_count is zero' do
+        it 'returns zero' do
+          namespace.add_developer(user)
+
+          post_query
+
+          expect(graphql_data_at(:ciCatalogResource)).to match(
+            a_graphql_entity_for(
+              open_merge_requests_count: 0
+            )
+          )
+        end
+      end
+    end
+  end
 end
diff --git a/ee/spec/requests/api/graphql/ci/catalog/resources_spec.rb b/ee/spec/requests/api/graphql/ci/catalog/resources_spec.rb
index b5dec039d242..cecd9166e8c3 100644
--- a/ee/spec/requests/api/graphql/ci/catalog/resources_spec.rb
+++ b/ee/spec/requests/api/graphql/ci/catalog/resources_spec.rb
@@ -454,4 +454,88 @@
       end
     end
   end
+
+  describe 'openIssuesCount' do
+    before do
+      stub_licensed_features(ci_namespace_catalog: true)
+      namespace.add_developer(user)
+    end
+
+    context 'when open_issues_count is requested' do
+      before_all do
+        create(:issue, :opened, project: project1)
+        create(:issue, :opened, project: project1)
+
+        create(:issue, :opened, project: project2)
+      end
+
+      let(:query) do
+        <<~GQL
+          query {
+            ciCatalogResources(projectPath: "#{project1.full_path}") {
+              nodes {
+                openIssuesCount
+              }
+            }
+          }
+        GQL
+      end
+
+      it 'returns the correct count' do
+        create(:catalog_resource, project: project2)
+
+        post_query
+
+        expect(graphql_data_at(:ciCatalogResources, :nodes)).to contain_exactly(
+          a_graphql_entity_for(
+            openIssuesCount: 2),
+          a_graphql_entity_for(
+            openIssuesCount: 1)
+        )
+      end
+
+      it_behaves_like 'avoids N+1 queries'
+    end
+  end
+
+  describe 'openMergeRequestsCount' do
+    before do
+      stub_licensed_features(ci_namespace_catalog: true)
+      namespace.add_developer(user)
+    end
+
+    context 'when open_merge_requests_count is requested' do
+      before_all do
+        create(:merge_request, :opened, source_project: project1)
+        create(:merge_request, :opened, source_project: project2)
+      end
+
+      let(:query) do
+        <<~GQL
+          query {
+            ciCatalogResources(projectPath: "#{project1.full_path}") {
+              nodes {
+                openMergeRequestsCount
+              }
+            }
+          }
+        GQL
+      end
+
+      it 'returns the correct count' do
+        create(:catalog_resource, project: project2)
+
+        post_query
+
+        expect(graphql_data_at(:ciCatalogResources, :nodes)).to contain_exactly(
+          a_graphql_entity_for(
+            openMergeRequestsCount: 1),
+          a_graphql_entity_for(
+            openMergeRequestsCount: 1)
+        )
+      end
+
+      it_behaves_like 'avoids N+1 queries'
+    end
+  end
 end
diff --git a/spec/graphql/types/merge_request_state_enum_spec.rb b/spec/graphql/types/merge_request_state_enum_spec.rb
index 6fc5803a5d06..9c286c54e159 100644
--- a/spec/graphql/types/merge_request_state_enum_spec.rb
+++ b/spec/graphql/types/merge_request_state_enum_spec.rb
@@ -8,6 +8,6 @@
   it_behaves_like 'issuable state'
 
   it 'exposes all the existing merge request states' do
-    expect(described_class.values.keys).to include('merged')
+    expect(described_class.values.keys).to include('merged', 'opened')
   end
 end
-- 
GitLab