From 6ca4ddae6404b7f13bff8080a148709a24de6b7b Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Sun, 30 Oct 2022 01:24:21 +0530 Subject: [PATCH 1/3] feat: add import project from remote support --- gitlab/v4/objects/projects.py | 45 +++++++++++++++++++ .../objects/test_project_import_export.py | 31 +++++++++++++ 2 files changed, 76 insertions(+) diff --git a/gitlab/v4/objects/projects.py b/gitlab/v4/objects/projects.py index 36e61f65d..f92671d50 100644 --- a/gitlab/v4/objects/projects.py +++ b/gitlab/v4/objects/projects.py @@ -822,6 +822,8 @@ def import_project( Args: file: Data or file object containing the project path: Name and path for the new project + name: The name of the project to import. If not provided, + defaults to the path of the project. namespace: The ID or path of the namespace that the project will be imported to overwrite: If True overwrite an existing project with the @@ -849,6 +851,49 @@ def import_project( "/projects/import", post_data=data, files=files, **kwargs ) + def import_project_from_remote( + self, + url: str, + path: str, + name: Optional[str] = None, + namespace: Optional[str] = None, + overwrite: bool = False, + override_params: Optional[Dict[str, Any]] = None, + **kwargs: Any, + ) -> Union[Dict[str, Any], requests.Response]: + """Import a project from an archive file stored on a remote URL. + + Args: + url: URL for the file containing the project data to import + path: Name and path for the new project + name: The name of the project to import. If not provided, + defaults to the path of the project. + namespace: The ID or path of the namespace that the project + will be imported to + overwrite: If True overwrite an existing project with the + same path + override_params: Set the specific settings for the project + **kwargs: Extra options to send to the server (e.g. sudo) + + Raises: + GitlabAuthenticationError: If authentication is not correct + GitlabListError: If the server failed to perform the request + + Returns: + A representation of the import status. + """ + data = {"path": path, "overwrite": str(overwrite), "url": url} + if override_params: + for k, v in override_params.items(): + data[f"override_params[{k}]"] = v + if name is not None: + data["name"] = name + if namespace: + data["namespace"] = namespace + return self.gitlab.http_post( + "/projects/remote-import", post_data=data, **kwargs + ) + def import_bitbucket_server( self, bitbucket_server_url: str, diff --git a/tests/unit/objects/test_project_import_export.py b/tests/unit/objects/test_project_import_export.py index 450acc0ad..bb41aefa8 100644 --- a/tests/unit/objects/test_project_import_export.py +++ b/tests/unit/objects/test_project_import_export.py @@ -29,6 +29,30 @@ def resp_import_project(): yield rsps +@pytest.fixture +def resp_import_project_from_remote(): + content = { + "id": 1, + "description": None, + "name": "remote-project", + "name_with_namespace": "Administrator / remote-project", + "path": "remote-project", + "path_with_namespace": "root/remote-project", + "created_at": "2018-02-13T09:05:58.023Z", + "import_status": "scheduled", + } + + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.POST, + url="http://localhost/api/v4/projects/remote-import", + json=content, + content_type="application/json", + status=200, + ) + yield rsps + + @pytest.fixture def resp_import_status(): content = { @@ -99,6 +123,13 @@ def test_import_project(gl, resp_import_project): assert project_import["import_status"] == "scheduled" +def test_import_project_from_remote(gl, resp_import_project_from_remote): + project_import = gl.projects.import_project_remote( + "https://whatever.com/url", "remote-project", "remote-project", "root" + ) + assert project_import["import_status"] == "scheduled" + + def test_import_project_with_override_params(gl, resp_import_project): project_import = gl.projects.import_project( "file", "api-project", override_params={"visibility": "private"} From 2d5f3418c9b47f13aa45e13abc50dd0e0da503a9 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Sun, 30 Oct 2022 02:28:56 +0530 Subject: [PATCH 2/3] test: fix import export test --- tests/unit/objects/test_project_import_export.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/objects/test_project_import_export.py b/tests/unit/objects/test_project_import_export.py index bb41aefa8..0394f5297 100644 --- a/tests/unit/objects/test_project_import_export.py +++ b/tests/unit/objects/test_project_import_export.py @@ -124,7 +124,7 @@ def test_import_project(gl, resp_import_project): def test_import_project_from_remote(gl, resp_import_project_from_remote): - project_import = gl.projects.import_project_remote( + project_import = gl.projects.import_project_from_remote( "https://whatever.com/url", "remote-project", "remote-project", "root" ) assert project_import["import_status"] == "scheduled" From 9857393ec625a926859adb6124021d4638005655 Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Tue, 1 Nov 2022 02:03:38 +0530 Subject: [PATCH 3/3] feat: fix func name, add func test, add docs --- docs/gl_objects/projects.rst | 9 +++++++++ gitlab/v4/objects/projects.py | 2 +- tests/functional/api/test_import_export.py | 14 ++++++++++++++ tests/unit/objects/test_project_import_export.py | 6 +++--- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/docs/gl_objects/projects.rst b/docs/gl_objects/projects.rst index e96f14c80..231aa50a0 100644 --- a/docs/gl_objects/projects.rst +++ b/docs/gl_objects/projects.rst @@ -342,6 +342,15 @@ Import the project into a namespace and override parameters:: override_params={'visibility': 'private'}, ) +Import the project using file stored on a remote URL:: + + output = gl.projects.remote_import( + url="https://whatever.com/url/file.tar.gz", + path="my_new_remote_project", + name="My New Remote Project", + namespace="my-group", + override_params={'visibility': 'private'}, + ) Project custom attributes ========================= diff --git a/gitlab/v4/objects/projects.py b/gitlab/v4/objects/projects.py index f92671d50..446e4f539 100644 --- a/gitlab/v4/objects/projects.py +++ b/gitlab/v4/objects/projects.py @@ -851,7 +851,7 @@ def import_project( "/projects/import", post_data=data, files=files, **kwargs ) - def import_project_from_remote( + def remote_import( self, url: str, path: str, diff --git a/tests/functional/api/test_import_export.py b/tests/functional/api/test_import_export.py index 32b85c6ce..83cccc69e 100644 --- a/tests/functional/api/test_import_export.py +++ b/tests/functional/api/test_import_export.py @@ -1,5 +1,7 @@ import time +import pytest + import gitlab @@ -64,3 +66,15 @@ def test_project_import_export(gl, project, temp_dir): count += 1 if count == 15: raise Exception("Project import taking too much time") + + +def test_project_remote_import(gl): + with pytest.raises(gitlab.exceptions.GitlabHttpError) as err_info: + gl.projects.remote_import( + "ftp://whatever.com/url", "remote-project", "remote-project", "root" + ) + assert err_info.value.response_code == 400 + assert ( + "File url is blocked: Only allowed schemes are https" + in err_info.value.error_message + ) diff --git a/tests/unit/objects/test_project_import_export.py b/tests/unit/objects/test_project_import_export.py index 0394f5297..72321ec68 100644 --- a/tests/unit/objects/test_project_import_export.py +++ b/tests/unit/objects/test_project_import_export.py @@ -30,7 +30,7 @@ def resp_import_project(): @pytest.fixture -def resp_import_project_from_remote(): +def resp_remote_import(): content = { "id": 1, "description": None, @@ -123,8 +123,8 @@ def test_import_project(gl, resp_import_project): assert project_import["import_status"] == "scheduled" -def test_import_project_from_remote(gl, resp_import_project_from_remote): - project_import = gl.projects.import_project_from_remote( +def test_remote_import(gl, resp_remote_import): + project_import = gl.projects.remote_import( "https://whatever.com/url", "remote-project", "remote-project", "root" ) assert project_import["import_status"] == "scheduled"