Skip to content

feat: add support for Groups API method transfer() #1837

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions gitlab/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ class GitlabTransferProjectError(GitlabOperationError):
pass


class GitlabGroupTransferError(GitlabOperationError):
pass


class GitlabProjectDeployKeyError(GitlabOperationError):
pass

Expand Down
24 changes: 23 additions & 1 deletion gitlab/v4/objects/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,34 @@ def transfer_project(self, project_id: int, **kwargs: Any) -> None:
path = f"/groups/{self.id}/projects/{project_id}"
self.manager.gitlab.http_post(path, **kwargs)

@cli.register_custom_action("Group", tuple(), ("group_id",))
@exc.on_http_error(exc.GitlabGroupTransferError)
def transfer(self, group_id: Optional[int] = None, **kwargs: Any) -> None:
"""Transfer the group to a new parent group or make it a top-level group.

Requires GitLab ≥14.6.

Args:
group_id: ID of the new parent group. When not specified,
the group to transfer is instead turned into a top-level group.
**kwargs: Extra options to send to the server (e.g. sudo)

Raises:
GitlabAuthenticationError: If authentication is not correct
GitlabGroupTransferError: If the group could not be transferred
"""
path = f"/groups/{self.encoded_id}/transfer"
post_data = {}
if group_id is not None:
post_data["group_id"] = group_id
self.manager.gitlab.http_post(path, post_data=post_data, **kwargs)

@cli.register_custom_action("Group", ("scope", "search"))
@exc.on_http_error(exc.GitlabSearchError)
def search(
self, scope: str, search: str, **kwargs: Any
) -> Union[gitlab.GitlabList, List[Dict[str, Any]]]:
"""Search the group resources matching the provided string.'
"""Search the group resources matching the provided string.

Args:
scope: Scope of the search
Expand Down
14 changes: 8 additions & 6 deletions tests/functional/api/test_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,17 +233,19 @@ def test_group_hooks(group):
hook.delete()


@pytest.mark.skip(reason="Pending #1807")
def test_group_transfer(gl, group):
transfer_group = gl.groups.create({"name": "transfer-test-group"})
assert group.namespace["path"] != group.full_path
transfer_group = gl.groups.create(
{"name": "transfer-test-group", "path": "transfer-test-group"}
)
transfer_group = gl.groups.get(transfer_group.id)
assert transfer_group.parent_id != group.id

transfer_group.transfer(group.id)

transferred_group = gl.projects.get(transfer_group.id)
assert transferred_group.namespace["path"] == group.full_path
transferred_group = gl.groups.get(transfer_group.id)
assert transferred_group.parent_id == group.id

transfer_group.transfer()

transferred_group = gl.projects.get(transfer_group.id)
transferred_group = gl.groups.get(transfer_group.id)
assert transferred_group.path == transferred_group.full_path
2 changes: 1 addition & 1 deletion tests/functional/fixtures/.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
GITLAB_IMAGE=gitlab/gitlab-ce
GITLAB_TAG=14.5.2-ce.0
GITLAB_TAG=14.6.2-ce.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sneaky... 😁

5 changes: 2 additions & 3 deletions tests/unit/objects/test_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ def resp_create_import(accepted_content):
def resp_transfer_group():
with responses.RequestsMock() as rsps:
rsps.add(
method=responses.PUT,
method=responses.POST,
url="http://localhost/api/v4/groups/1/transfer",
json=content,
content_type="application/json",
status=200,
match=[
responses.matchers.json_params_matcher({"namespace": "test-namespace"})
responses.matchers.json_params_matcher({"group_id": "test-namespace"})
],
)
yield rsps
Expand Down Expand Up @@ -170,7 +170,6 @@ def test_refresh_group_import_status(group, resp_groups):
assert group_import.import_status == "finished"


@pytest.mark.skip("Pending #1807")
def test_transfer_group(gl, resp_transfer_group):
group = gl.groups.get(1, lazy=True)
group.transfer("test-namespace")