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 36e61f65d..446e4f539 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 remote_import( + 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/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 450acc0ad..72321ec68 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_remote_import(): + 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_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" + + def test_import_project_with_override_params(gl, resp_import_project): project_import = gl.projects.import_project( "file", "api-project", override_params={"visibility": "private"}