From 4cfaa2fd44b64459f6fc268a91d4469284c0e768 Mon Sep 17 00:00:00 2001 From: Nejc Habjan Date: Tue, 7 Apr 2020 00:55:33 +0200 Subject: [PATCH] feat(api): add support for remote mirrors API (#1056) --- docs/api-objects.rst | 1 + docs/gl_objects/remote_mirrors.rst | 34 ++++++++++ gitlab/tests/objects/test_projects.py | 94 +++++++++++++++++++++++++++ gitlab/v4/objects.py | 13 ++++ tools/python_test_v4.py | 17 +++++ 5 files changed, 159 insertions(+) create mode 100644 docs/gl_objects/remote_mirrors.rst diff --git a/docs/api-objects.rst b/docs/api-objects.rst index 32f0d0c4c..32852f8fd 100644 --- a/docs/api-objects.rst +++ b/docs/api-objects.rst @@ -37,6 +37,7 @@ API examples gl_objects/projects gl_objects/protected_branches gl_objects/runners + gl_objects/remote_mirrors gl_objects/repositories gl_objects/repository_tags gl_objects/search diff --git a/docs/gl_objects/remote_mirrors.rst b/docs/gl_objects/remote_mirrors.rst new file mode 100644 index 000000000..ea4f72c41 --- /dev/null +++ b/docs/gl_objects/remote_mirrors.rst @@ -0,0 +1,34 @@ +########## +Project Remote Mirrors +########## + +Remote Mirrors allow you to set up push mirroring for a project. + +References +========== + +* v4 API: + + + :class:`gitlab.v4.objects.ProjectRemoteMirror` + + :class:`gitlab.v4.objects.ProjectRemoteMirrorManager` + + :attr:`gitlab.v4.objects.Project.remote_mirrors` + +* GitLab API: https://docs.gitlab.com/ce/api/remote_mirrors.html + +Examples +-------- + +Get the list of a project's remote mirrors:: + + mirrors = project.remote_mirrors.list() + +Create (and enable) a remote mirror for a project:: + + mirror = project.wikis.create({'url': 'https://gitlab.com/example.git', + 'enabled': True}) + +Update an existing remote mirror's attributes:: + + mirror.enabled = False + mirror.only_protected_branches = True + mirror.save() diff --git a/gitlab/tests/objects/test_projects.py b/gitlab/tests/objects/test_projects.py index 1c2347aa2..48347f92f 100644 --- a/gitlab/tests/objects/test_projects.py +++ b/gitlab/tests/objects/test_projects.py @@ -90,6 +90,77 @@ def resp_import_github(url, request): return response(200, content, headers, None, 25, request) +@urlmatch( + scheme="http", + netloc="localhost", + path="/api/v4/projects/1/remote_mirrors", + method="get", +) +def resp_get_remote_mirrors(url, request): + """Mock for Project Remote Mirrors GET response.""" + content = """[ + { + "enabled": true, + "id": 101486, + "last_error": null, + "last_successful_update_at": "2020-01-06T17:32:02.823Z", + "last_update_at": "2020-01-06T17:32:02.823Z", + "last_update_started_at": "2020-01-06T17:31:55.864Z", + "only_protected_branches": true, + "update_status": "finished", + "url": "https://*****:*****@gitlab.com/gitlab-org/security/gitlab.git" + } + ]""" + content = content.encode("utf-8") + return response(200, content, headers, None, 5, request) + + +@urlmatch( + scheme="http", + netloc="localhost", + path="/api/v4/projects/1/remote_mirrors", + method="post", +) +def resp_create_remote_mirror(url, request): + """Mock for Project Remote Mirrors POST response.""" + content = """{ + "enabled": false, + "id": 101486, + "last_error": null, + "last_successful_update_at": null, + "last_update_at": null, + "last_update_started_at": null, + "only_protected_branches": false, + "update_status": "none", + "url": "https://*****:*****@example.com/gitlab/example.git" + }""" + content = content.encode("utf-8") + return response(200, content, headers, None, 5, request) + + +@urlmatch( + scheme="http", + netloc="localhost", + path="/api/v4/projects/1/remote_mirrors/1", + method="put", +) +def resp_update_remote_mirror(url, request): + """Mock for Project Remote Mirrors PUT response.""" + content = """{ + "enabled": false, + "id": 101486, + "last_error": null, + "last_successful_update_at": "2020-01-06T17:32:02.823Z", + "last_update_at": "2020-01-06T17:32:02.823Z", + "last_update_started_at": "2020-01-06T17:31:55.864Z", + "only_protected_branches": true, + "update_status": "finished", + "url": "https://*****:*****@gitlab.com/gitlab-org/security/gitlab.git" + }""" + content = content.encode("utf-8") + return response(200, content, headers, None, 5, request) + + class TestProject(unittest.TestCase): """Base class for GitLab Project tests.""" @@ -262,3 +333,26 @@ def test_import_github(self): self.assertEqual(ret["name"], name) self.assertEqual(ret["full_path"], "/".join((base_path, name))) self.assertTrue(ret["full_name"].endswith(name)) + + +class TestProjectRemoteMirrors(TestProject): + @with_httmock(resp_get_remote_mirrors) + def test_list_project_remote_mirrors(self): + mirrors = self.project.remote_mirrors.list() + self.assertIsInstance(mirrors, list) + self.assertIsInstance(mirrors[0], ProjectRemoteMirror) + self.assertTrue(mirrors[0].enabled) + + @with_httmock(resp_create_remote_mirror) + def test_create_project_remote_mirror(self): + mirror = self.project.remote_mirrors.create({"url": "https://example.com"}) + self.assertIsInstance(mirror, ProjectRemoteMirror) + self.assertEqual(mirror.update_status, "none") + + @with_httmock(resp_create_remote_mirror, resp_update_remote_mirror) + def test_update_project_remote_mirror(self): + mirror = self.project.remote_mirrors.create({"url": "https://example.com"}) + mirror.only_protected_branches = True + mirror.save() + self.assertEqual(mirror.update_status, "finished") + self.assertTrue(mirror.only_protected_branches) diff --git a/gitlab/v4/objects.py b/gitlab/v4/objects.py index 985519671..25d890ecb 100644 --- a/gitlab/v4/objects.py +++ b/gitlab/v4/objects.py @@ -1745,6 +1745,18 @@ def delete_in_bulk(self, name_regex=".*", **kwargs): self.gitlab.http_delete(self.path, query_data=data, **kwargs) +class ProjectRemoteMirror(SaveMixin, RESTObject): + pass + + +class ProjectRemoteMirrorManager(ListMixin, CreateMixin, UpdateMixin, RESTManager): + _path = "/projects/%(project_id)s/remote_mirrors" + _obj_cls = ProjectRemoteMirror + _from_parent_attrs = {"project_id": "id"} + _create_attrs = (("url",), ("enabled", "only_protected_branches")) + _update_attrs = (tuple(), ("enabled", "only_protected_branches")) + + class ProjectBoardList(SaveMixin, ObjectDeleteMixin, RESTObject): pass @@ -4246,6 +4258,7 @@ class Project(SaveMixin, ObjectDeleteMixin, RESTObject): ("pipelineschedules", "ProjectPipelineScheduleManager"), ("pushrules", "ProjectPushRulesManager"), ("releases", "ProjectReleaseManager"), + ("remote_mirrors", "ProjectRemoteMirrorManager"), ("repositories", "ProjectRegistryRepositoryManager"), ("runners", "ProjectRunnerManager"), ("services", "ProjectServiceManager"), diff --git a/tools/python_test_v4.py b/tools/python_test_v4.py index 076329b19..649f4139a 100644 --- a/tools/python_test_v4.py +++ b/tools/python_test_v4.py @@ -1047,6 +1047,23 @@ assert len(release_test_project.releases.list()) == 0 release_test_project.delete() +# project remote mirrors +mirror_url = "http://gitlab.test/root/mirror.git" + +# create remote mirror +mirror = admin_project.remote_mirrors.create({"url": mirror_url}) +assert mirror.url == mirror_url + +# update remote mirror +mirror.enabled = True +mirror.save() + +# list remote mirrors +mirror = admin_project.remote_mirrors.list()[0] +assert isinstance(mirror, gitlab.v4.objects.ProjectRemoteMirror) +assert mirror.url == mirror_url +assert mirror.enabled is True + # status message = "Test" emoji = "thumbsup"