diff options
author | Nejc Habjan <hab.nejc@gmail.com> | 2021-05-29 23:47:46 +0200 |
---|---|---|
committer | John Villalovos <john@sodarock.com> | 2021-05-29 21:06:15 -0700 |
commit | 1b70580020825adf2d1f8c37803bc4655a97be41 (patch) | |
tree | 8e754db6fb365ce7c7fa01e51e527e5fdded630f | |
parent | 237b97ceb0614821e59ea041f43a9806b65cdf8c (diff) | |
download | gitlab-1b70580020825adf2d1f8c37803bc4655a97be41.tar.gz |
feat(objects): add support for descendant groups API
-rw-r--r-- | docs/gl_objects/groups.rst | 25 | ||||
-rw-r--r-- | gitlab/v4/objects/groups.py | 17 | ||||
-rw-r--r-- | tests/functional/api/test_groups.py | 1 | ||||
-rw-r--r-- | tests/unit/objects/test_groups.py | 58 |
4 files changed, 101 insertions, 0 deletions
diff --git a/docs/gl_objects/groups.rst b/docs/gl_objects/groups.rst index 9f1b049..596db0a 100644 --- a/docs/gl_objects/groups.rst +++ b/docs/gl_objects/groups.rst @@ -167,6 +167,31 @@ List the subgroups for a group:: real_group = gl.groups.get(subgroup_id, lazy=True) real_group.issues.list() +Descendant Groups +================= + +Reference +--------- + +* v4 API: + + + :class:`gitlab.v4.objects.GroupDescendantGroup` + + :class:`gitlab.v4.objects.GroupDescendantGroupManager` + + :attr:`gitlab.v4.objects.Group.descendant_groups` + +Examples +-------- + +List the descendant groups of a group:: + + descendant_groups = group.descendant_groups.list() + +.. note:: + + Like the ``GroupSubgroup`` objects described above, ``GroupDescendantGroup`` + objects do not expose the same API as the ``Group`` objects. Create a new + ``Group`` object instead if needed, as shown in the subgroup example. + Group custom attributes ======================= diff --git a/gitlab/v4/objects/groups.py b/gitlab/v4/objects/groups.py index e29edc8..860a056 100644 --- a/gitlab/v4/objects/groups.py +++ b/gitlab/v4/objects/groups.py @@ -31,6 +31,8 @@ from .variables import GroupVariableManager # noqa: F401 __all__ = [ "Group", "GroupManager", + "GroupDescendantGroup", + "GroupDescendantGroupManager", "GroupSubgroup", "GroupSubgroupManager", ] @@ -45,6 +47,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject): ("billable_members", "GroupBillableMemberManager"), ("boards", "GroupBoardManager"), ("customattributes", "GroupCustomAttributeManager"), + ("descendant_groups", "GroupDescendantGroupManager"), ("exports", "GroupExportManager"), ("epics", "GroupEpicManager"), ("imports", "GroupImportManager"), @@ -310,3 +313,17 @@ class GroupSubgroupManager(ListMixin, RESTManager): "min_access_level", ) _types = {"skip_groups": types.ListAttribute} + + +class GroupDescendantGroup(RESTObject): + pass + + +class GroupDescendantGroupManager(GroupSubgroupManager): + """ + This manager inherits from GroupSubgroupManager as descendant groups + share all attributes with subgroups, except the path and object class. + """ + + _path = "/groups/%(group_id)s/descendant_groups" + _obj_cls = GroupDescendantGroup diff --git a/tests/functional/api/test_groups.py b/tests/functional/api/test_groups.py index eae2d9b..c2b8cbd 100644 --- a/tests/functional/api/test_groups.py +++ b/tests/functional/api/test_groups.py @@ -32,6 +32,7 @@ def test_groups(gl): assert len(gl.groups.list(search="oup1")) == 1 assert group3.parent_id == p_id assert group2.subgroups.list()[0].id == group3.id + assert group2.descendant_groups.list()[0].id == group3.id filtered_groups = gl.groups.list(skip_groups=[group3.id, group4.id]) assert group3 not in filtered_groups diff --git a/tests/unit/objects/test_groups.py b/tests/unit/objects/test_groups.py index d4786f4..37023d8 100644 --- a/tests/unit/objects/test_groups.py +++ b/tests/unit/objects/test_groups.py @@ -2,10 +2,41 @@ GitLab API: https://docs.gitlab.com/ce/api/groups.html """ +import re + import pytest import responses import gitlab +from gitlab.v4.objects import GroupDescendantGroup, GroupSubgroup + +subgroup_descgroup_content = [ + { + "id": 2, + "name": "Bar Group", + "path": "foo/bar", + "description": "A subgroup of Foo Group", + "visibility": "public", + "share_with_group_lock": False, + "require_two_factor_authentication": False, + "two_factor_grace_period": 48, + "project_creation_level": "developer", + "auto_devops_enabled": None, + "subgroup_creation_level": "owner", + "emails_disabled": None, + "mentions_disabled": None, + "lfs_enabled": True, + "default_branch_protection": 2, + "avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/bar.jpg", + "web_url": "http://gitlab.example.com/groups/foo/bar", + "request_access_enabled": False, + "full_name": "Bar Group", + "full_path": "foo/bar", + "file_template_project_id": 1, + "parent_id": 123, + "created_at": "2020-01-15T12:36:29.590Z", + }, +] @pytest.fixture @@ -38,6 +69,21 @@ def resp_groups(): @pytest.fixture +def resp_list_subgroups_descendant_groups(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.GET, + url=re.compile( + r"http://localhost/api/v4/groups/1/(subgroups|descendant_groups)" + ), + json=subgroup_descgroup_content, + content_type="application/json", + status=200, + ) + yield rsps + + +@pytest.fixture def resp_create_import(accepted_content): with responses.RequestsMock() as rsps: rsps.add( @@ -71,6 +117,18 @@ def test_create_group_export(group, resp_export): assert export.message == "202 Accepted" +def test_list_group_subgroups(group, resp_list_subgroups_descendant_groups): + subgroups = group.subgroups.list() + assert isinstance(subgroups[0], GroupSubgroup) + assert subgroups[0].path == subgroup_descgroup_content[0]["path"] + + +def test_list_group_descendant_groups(group, resp_list_subgroups_descendant_groups): + descendant_groups = group.descendant_groups.list() + assert isinstance(descendant_groups[0], GroupDescendantGroup) + assert descendant_groups[0].path == subgroup_descgroup_content[0]["path"] + + @pytest.mark.skip("GitLab API endpoint not implemented") def test_refresh_group_export_status(group, resp_export): export = group.exports.create() |