Repository: python-gitlab/python-gitlab

Issue:
Not possible to get issues statistics
I do not see a way to obtain issue statistics: https://docs.gitlab.com/ee/api/issues_statistics.html#get-project-issues-statistics


Discussion:
I didn't even know that these existed. Nobody requested these before. I would be happy to review any MRs regarding this.

Resolving patch:
diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py
--- a/gitlab/v4/objects.py
+++ b/gitlab/v4/objects.py
@@ -3997,6 +3997,26 @@ class ProjectImportManager(GetWithoutIdMixin, RESTManager):
     _from_parent_attrs = {"project_id": "id"}
 
 
+class ProjectAdditionalStatistics(RefreshMixin, RESTObject):
+    _id_attr = None
+
+
+class ProjectAdditionalStatisticsManager(GetWithoutIdMixin, RESTManager):
+    _path = "/projects/%(project_id)s/statistics"
+    _obj_cls = ProjectAdditionalStatistics
+    _from_parent_attrs = {"project_id": "id"}
+
+
+class ProjectIssuesStatistics(RefreshMixin, RESTObject):
+    _id_attr = None
+
+
+class ProjectIssuesStatisticsManager(GetWithoutIdMixin, RESTManager):
+    _path = "/projects/%(project_id)s/issues_statistics"
+    _obj_cls = ProjectIssuesStatistics
+    _from_parent_attrs = {"project_id": "id"}
+
+
 class Project(SaveMixin, ObjectDeleteMixin, RESTObject):
     _short_print_attr = "path"
     _managers = (
@@ -4042,6 +4062,8 @@ class Project(SaveMixin, ObjectDeleteMixin, RESTObject):
         ("variables", "ProjectVariableManager"),
         ("wikis", "ProjectWikiManager"),
         ("clusters", "ProjectClusterManager"),
+        ("additionalstatistics", "ProjectAdditionalStatisticsManager"),
+        ("issuesstatistics", "ProjectIssuesStatisticsManager"),
     )
 
     @cli.register_custom_action("Project", ("submodule", "branch", "commit_sha"))


Test patch:
diff --git a/gitlab/tests/test_gitlab.py b/gitlab/tests/test_gitlab.py
--- a/gitlab/tests/test_gitlab.py
+++ b/gitlab/tests/test_gitlab.py
@@ -553,6 +553,62 @@ def resp_get_environment(url, request):
             self.assertEqual(environment.last_deployment, "sometime")
             self.assertEqual(environment.name, "environment_name")
 
+    def test_project_additional_statistics(self):
+        @urlmatch(
+            scheme="http", netloc="localhost", path="/api/v4/projects/1$", method="get"
+        )
+        def resp_get_project(url, request):
+            headers = {"content-type": "application/json"}
+            content = '{"name": "name", "id": 1}'.encode("utf-8")
+            return response(200, content, headers, None, 5, request)
+
+        @urlmatch(
+            scheme="http",
+            netloc="localhost",
+            path="/api/v4/projects/1/statistics",
+            method="get",
+        )
+        def resp_get_environment(url, request):
+            headers = {"content-type": "application/json"}
+            content = """{"fetches": {"total": 50, "days": [{"count": 10, "date": "2018-01-10"}]}}""".encode(
+                "utf-8"
+            )
+            return response(200, content, headers, None, 5, request)
+
+        with HTTMock(resp_get_project, resp_get_environment):
+            project = self.gl.projects.get(1)
+            statistics = project.additionalstatistics.get()
+            self.assertIsInstance(statistics, ProjectAdditionalStatistics)
+            self.assertEqual(statistics.fetches["total"], 50)
+
+    def test_project_issues_statistics(self):
+        @urlmatch(
+            scheme="http", netloc="localhost", path="/api/v4/projects/1$", method="get"
+        )
+        def resp_get_project(url, request):
+            headers = {"content-type": "application/json"}
+            content = '{"name": "name", "id": 1}'.encode("utf-8")
+            return response(200, content, headers, None, 5, request)
+
+        @urlmatch(
+            scheme="http",
+            netloc="localhost",
+            path="/api/v4/projects/1/issues_statistics",
+            method="get",
+        )
+        def resp_get_environment(url, request):
+            headers = {"content-type": "application/json"}
+            content = """{"statistics": {"counts": {"all": 20, "closed": 5, "opened": 15}}}""".encode(
+                "utf-8"
+            )
+            return response(200, content, headers, None, 5, request)
+
+        with HTTMock(resp_get_project, resp_get_environment):
+            project = self.gl.projects.get(1)
+            statistics = project.issuesstatistics.get()
+            self.assertIsInstance(statistics, ProjectIssuesStatistics)
+            self.assertEqual(statistics.statistics["counts"]["all"], 20)
+
     def test_groups(self):
         @urlmatch(
             scheme="http", netloc="localhost", path="/api/v4/groups/1", method="get"