From db0b00a905c14d52eaca831fcc9243f33d2f092d Mon Sep 17 00:00:00 2001 From: Mitar Date: Mon, 9 Dec 2019 23:40:29 -0800 Subject: [PATCH 1/4] feat: adding project stats Fixes #967 --- gitlab/v4/objects.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py index 89e3259b0..e957a3642 100644 --- a/gitlab/v4/objects.py +++ b/gitlab/v4/objects.py @@ -3997,6 +3997,16 @@ 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 Project(SaveMixin, ObjectDeleteMixin, RESTObject): _short_print_attr = "path" _managers = ( @@ -4042,6 +4052,7 @@ class Project(SaveMixin, ObjectDeleteMixin, RESTObject): ("variables", "ProjectVariableManager"), ("wikis", "ProjectWikiManager"), ("clusters", "ProjectClusterManager"), + ("additionalstatistics", "ProjectAdditionalStatisticsManager"), ) @cli.register_custom_action("Project", ("submodule", "branch", "commit_sha")) From 482e57ba716c21cd7b315e5803ecb3953c479b33 Mon Sep 17 00:00:00 2001 From: Mitar Date: Mon, 9 Dec 2019 23:51:08 -0800 Subject: [PATCH 2/4] feat: access project's issues statistics Fixes #966 --- gitlab/v4/objects.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py index e957a3642..91b946dc8 100644 --- a/gitlab/v4/objects.py +++ b/gitlab/v4/objects.py @@ -4007,6 +4007,16 @@ class ProjectAdditionalStatisticsManager(GetWithoutIdMixin, RESTManager): _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 = ( @@ -4053,6 +4063,7 @@ class Project(SaveMixin, ObjectDeleteMixin, RESTObject): ("wikis", "ProjectWikiManager"), ("clusters", "ProjectClusterManager"), ("additionalstatistics", "ProjectAdditionalStatisticsManager"), + ("issuesstatistics", "ProjectIssuesStatisticsManager"), ) @cli.register_custom_action("Project", ("submodule", "branch", "commit_sha")) From 8c84cbf6374e466f21d175206836672b3dadde20 Mon Sep 17 00:00:00 2001 From: Mitar Date: Thu, 12 Dec 2019 21:54:23 -0800 Subject: [PATCH 3/4] docs: added docs for statistics --- docs/gl_objects/projects.rst | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/docs/gl_objects/projects.rst b/docs/gl_objects/projects.rst index d76684755..f1eca382d 100644 --- a/docs/gl_objects/projects.rst +++ b/docs/gl_objects/projects.rst @@ -754,3 +754,54 @@ Protect a single repository tag or several project repository tags using a wildc Unprotect the given protected tag or wildcard protected tag.:: protected_tag.delete() + +Additional project statistics +============================= + +Reference +--------- + +* v4 API: + + + :class:`gitlab.v4.objects.ProjectAdditionalStatistics` + + :class:`gitlab.v4.objects.ProjectAdditionalStatisticsManager` + + :attr:`gitlab.v4.objects.Project.additionalstatistics` + +* GitLab API: https://docs.gitlab.com/ce/api/project_statistics.html + +Examples +--------- + +Get all additional statistics of a project:: + + statistics = project.additionalstatistics.get() + +Get total fetches in last 30 days of a project:: + + total_fetches = project.additionalstatistics.get()['fetches']['total'] + +Project issues statistics +========================= + +Reference +--------- + +* v4 API: + + + :class:`gitlab.v4.objects.ProjectIssuesStatistics` + + :class:`gitlab.v4.objects.ProjectIssuesStatisticsManager` + + :attr:`gitlab.v4.objects.Project.issuesstatistics` + +* GitLab API: https://docs.gitlab.com/ce/api/issues_statistics.html#get-project-issues-statistics + +Examples +--------- + +Get statistics of all issues in a project:: + + statistics = project.issuesstatistics.get() + +Get statistics of issues in a project with ``foobar`` in ``title`` and +``description``:: + + statistics = project.issuesstatistics.get(search='foobar') From 8760efc89bac394b01218b48dd3fcbef30c8b9a2 Mon Sep 17 00:00:00 2001 From: Mitar Date: Thu, 12 Dec 2019 22:08:58 -0800 Subject: [PATCH 4/4] test: added tests for statistics --- gitlab/tests/test_gitlab.py | 56 +++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/gitlab/tests/test_gitlab.py b/gitlab/tests/test_gitlab.py index 7449b3a66..5bf373a13 100644 --- 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"