From 761ff6741761bea1e7ed092df79f3a57dbaec9b8 Mon Sep 17 00:00:00 2001 From: Isaac Philip <4974658+isaac-philip@users.noreply.github.com> Date: Thu, 15 Feb 2024 15:47:19 +0530 Subject: [PATCH 1/7] feat(functional): merge train -> merge request :> status fetch --- gitlab/v4/objects/merge_trains.py | 28 ++++++++++++++++++++----- gitlab/v4/objects/projects.py | 2 +- tests/unit/objects/test_merge_trains.py | 26 ++++++++++++++++++++++- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/gitlab/v4/objects/merge_trains.py b/gitlab/v4/objects/merge_trains.py index a1c5a447d..026570494 100644 --- a/gitlab/v4/objects/merge_trains.py +++ b/gitlab/v4/objects/merge_trains.py @@ -1,14 +1,32 @@ -from gitlab.base import RESTObject -from gitlab.mixins import ListMixin +from gitlab.base import RESTManager, RESTObject +from gitlab.mixins import CRUDMixin, GetMixin, ListMixin +from gitlab.types import RequiredOptional -__all__ = ["ProjectMergeTrain", "ProjectMergeTrainManager"] +__all__ = [ + "ProjectMergeTrain", + "ProjectMergeTrainManager", + "ProjectMergeTrainMergeRequest", + "ProjectMergeTrainMergeRequestManager", +] -class ProjectMergeTrain(RESTObject): +class ProjectMergeTrainMergeRequest(RESTObject): pass -class ProjectMergeTrainManager(ListMixin[ProjectMergeTrain]): +class ProjectMergeTrainMergeRequestManager(CRUDMixin, RESTManager): + _path = "/projects/{project_id}/merge_trains/merge_requests" + _obj_cls = ProjectMergeTrainMergeRequest + _from_parent_attrs = {"project_id": "project_id"} + + _update_attrs = RequiredOptional(optional=("position",)) + + +class ProjectMergeTrain(RESTObject): + merge_requests: ProjectMergeTrainMergeRequestManager + + +class ProjectMergeTrainManager(GetMixin, ListMixin, RESTManager): _path = "/projects/{project_id}/merge_trains" _obj_cls = ProjectMergeTrain _from_parent_attrs = {"project_id": "id"} diff --git a/gitlab/v4/objects/projects.py b/gitlab/v4/objects/projects.py index b415a8b98..f74fd64b1 100644 --- a/gitlab/v4/objects/projects.py +++ b/gitlab/v4/objects/projects.py @@ -64,7 +64,7 @@ ProjectApprovalRuleManager, ) from .merge_requests import ProjectMergeRequestManager # noqa: F401 -from .merge_trains import ProjectMergeTrainManager # noqa: F401 +from .merge_trains import ProjectMergeTrainManager from .milestones import ProjectMilestoneManager # noqa: F401 from .notes import ProjectNoteManager # noqa: F401 from .notification_settings import ProjectNotificationSettingsManager # noqa: F401 diff --git a/tests/unit/objects/test_merge_trains.py b/tests/unit/objects/test_merge_trains.py index f58d04422..1880ab3cf 100644 --- a/tests/unit/objects/test_merge_trains.py +++ b/tests/unit/objects/test_merge_trains.py @@ -6,7 +6,7 @@ import pytest import responses -from gitlab.v4.objects import ProjectMergeTrain +from gitlab.v4.objects import ProjectMergeTrain, ProjectMergeTrainMergeRequest mr_content = { "id": 110, @@ -60,7 +60,31 @@ def resp_list_merge_trains(): yield rsps +@pytest.fixture +def resp_merge_trains_merge_request_get(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.GET, + url="http://localhost/api/v4/projects/1/merge_trains/merge_requests/123", + json=mr_content, + content_type="application/json", + status=200, + ) + yield rsps + + def test_list_project_merge_requests(project, resp_list_merge_trains): merge_trains = project.merge_trains.list() assert isinstance(merge_trains[0], ProjectMergeTrain) assert merge_trains[0].id == mr_content["id"] + + +def test_merge_trains_status_merge_request( + project, resp_merge_trains_merge_request_get +): + # flow will be : project -> merge_trains : -> get merge_requests -> merge_request_iod + merge_train_mr: ProjectMergeTrainMergeRequest = project.merge_trains.get( + 1, lazy=True + ).merge_requests.get(123) + assert isinstance(merge_train_mr, ProjectMergeTrainMergeRequest) + assert merge_train_mr.get_id() == 110 From e10ba0caff7a371aca49c2743003151a445546f3 Mon Sep 17 00:00:00 2001 From: Isaac Philip <4974658+isaac-philip@users.noreply.github.com> Date: Thu, 15 Feb 2024 15:47:19 +0530 Subject: [PATCH 2/7] feat(functional): merge train -> merge request :> status fetch --- gitlab/v4/objects/merge_trains.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/gitlab/v4/objects/merge_trains.py b/gitlab/v4/objects/merge_trains.py index 026570494..732c6b8e3 100644 --- a/gitlab/v4/objects/merge_trains.py +++ b/gitlab/v4/objects/merge_trains.py @@ -1,6 +1,5 @@ from gitlab.base import RESTManager, RESTObject from gitlab.mixins import CRUDMixin, GetMixin, ListMixin -from gitlab.types import RequiredOptional __all__ = [ "ProjectMergeTrain", @@ -19,8 +18,6 @@ class ProjectMergeTrainMergeRequestManager(CRUDMixin, RESTManager): _obj_cls = ProjectMergeTrainMergeRequest _from_parent_attrs = {"project_id": "project_id"} - _update_attrs = RequiredOptional(optional=("position",)) - class ProjectMergeTrain(RESTObject): merge_requests: ProjectMergeTrainMergeRequestManager From cb4e0155437e0a0a916b846e714a62cdaecf7f25 Mon Sep 17 00:00:00 2001 From: Isaac Philip <4974658+isaac-philip@users.noreply.github.com> Date: Sat, 2 Mar 2024 19:33:21 +0530 Subject: [PATCH 3/7] feat(functional): #2547 merge-train api for status and add mr Signed-off-by: Isaac Philip <4974658+isaac-philip@users.noreply.github.com> --- gitlab/v4/objects/merge_trains.py | 10 +++++-- tests/unit/objects/test_merge_trains.py | 37 ++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/gitlab/v4/objects/merge_trains.py b/gitlab/v4/objects/merge_trains.py index 732c6b8e3..be3fb75ed 100644 --- a/gitlab/v4/objects/merge_trains.py +++ b/gitlab/v4/objects/merge_trains.py @@ -1,5 +1,6 @@ from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, GetMixin, ListMixin +from gitlab.mixins import GetMixin, ListMixin, UpdateMethod, UpdateMixin +from gitlab.types import RequiredOptional __all__ = [ "ProjectMergeTrain", @@ -13,10 +14,15 @@ class ProjectMergeTrainMergeRequest(RESTObject): pass -class ProjectMergeTrainMergeRequestManager(CRUDMixin, RESTManager): +class ProjectMergeTrainMergeRequestManager(GetMixin, UpdateMixin, RESTManager): _path = "/projects/{project_id}/merge_trains/merge_requests" _obj_cls = ProjectMergeTrainMergeRequest _from_parent_attrs = {"project_id": "project_id"} + _update_method: UpdateMethod = UpdateMethod.POST + + _update_attrs = RequiredOptional( + optional=("sha", "squash", "when_pipeline_succeeds"), + ) class ProjectMergeTrain(RESTObject): diff --git a/tests/unit/objects/test_merge_trains.py b/tests/unit/objects/test_merge_trains.py index 1880ab3cf..7f8e48d8b 100644 --- a/tests/unit/objects/test_merge_trains.py +++ b/tests/unit/objects/test_merge_trains.py @@ -46,6 +46,10 @@ "duration": 70, } +merge_train_update = mr_content.copy() +merge_train_update["id"] = 123 +merge_train_update["pipeline"]["sha"] = "ef33a3zxc3" + @pytest.fixture def resp_list_merge_trains(): @@ -65,7 +69,7 @@ def resp_merge_trains_merge_request_get(): with responses.RequestsMock() as rsps: rsps.add( method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_trains/merge_requests/123", + url="http://localhost/api/v4/projects/1/merge_trains/merge_requests/110", json=mr_content, content_type="application/json", status=200, @@ -73,18 +77,43 @@ def resp_merge_trains_merge_request_get(): yield rsps +@pytest.fixture +def resp_merge_trains_merge_request_post(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.POST, + url="http://localhost/api/v4/projects/1/merge_trains/merge_requests/123", + json=[merge_train_update], + content_type="application/json", + status=200, + ) + yield rsps + + def test_list_project_merge_requests(project, resp_list_merge_trains): merge_trains = project.merge_trains.list() assert isinstance(merge_trains[0], ProjectMergeTrain) assert merge_trains[0].id == mr_content["id"] -def test_merge_trains_status_merge_request( +def test_merge_trains_status_merge_request_get_status( project, resp_merge_trains_merge_request_get ): - # flow will be : project -> merge_trains : -> get merge_requests -> merge_request_iod merge_train_mr: ProjectMergeTrainMergeRequest = project.merge_trains.get( 1, lazy=True - ).merge_requests.get(123) + ).merge_requests.get(110) assert isinstance(merge_train_mr, ProjectMergeTrainMergeRequest) assert merge_train_mr.get_id() == 110 + assert merge_train_mr.pipeline.get("status") == mr_content["pipeline"]["status"] + + +def test_merge_train_add_merge_request(project, resp_merge_trains_merge_request_post): + merge_train: ProjectMergeTrain = project.merge_trains.get(1, lazy=True) + merge_requests_update = merge_train.merge_requests.update( + 123, new_data={"sha": "ef33a3zxc3"} + ) + assert isinstance(merge_train, ProjectMergeTrain) + assert ( + merge_requests_update[0]["pipeline"]["sha"] + == merge_train_update["pipeline"]["sha"] + ) From 775cd78ab2cb43f3f784647bf334cbc09ea592bc Mon Sep 17 00:00:00 2001 From: Isaac Philip <4974658+isaac-philip@users.noreply.github.com> Date: Mon, 3 Mar 2025 00:54:25 +0530 Subject: [PATCH 4/7] feat(functional): #2547 merge-train api for status and add mr - test data modifications Signed-off-by: Isaac Philip <4974658+isaac-philip@users.noreply.github.com> --- gitlab/v4/objects/merge_trains.py | 4 ++-- tests/unit/objects/test_merge_trains.py | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/gitlab/v4/objects/merge_trains.py b/gitlab/v4/objects/merge_trains.py index be3fb75ed..80469a481 100644 --- a/gitlab/v4/objects/merge_trains.py +++ b/gitlab/v4/objects/merge_trains.py @@ -1,5 +1,5 @@ from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import GetMixin, ListMixin, UpdateMethod, UpdateMixin +from gitlab.mixins import CRUDMixin, GetMixin, ListMixin, UpdateMethod from gitlab.types import RequiredOptional __all__ = [ @@ -14,7 +14,7 @@ class ProjectMergeTrainMergeRequest(RESTObject): pass -class ProjectMergeTrainMergeRequestManager(GetMixin, UpdateMixin, RESTManager): +class ProjectMergeTrainMergeRequestManager(CRUDMixin, RESTManager): _path = "/projects/{project_id}/merge_trains/merge_requests" _obj_cls = ProjectMergeTrainMergeRequest _from_parent_attrs = {"project_id": "project_id"} diff --git a/tests/unit/objects/test_merge_trains.py b/tests/unit/objects/test_merge_trains.py index 7f8e48d8b..fa5fe6221 100644 --- a/tests/unit/objects/test_merge_trains.py +++ b/tests/unit/objects/test_merge_trains.py @@ -11,7 +11,7 @@ mr_content = { "id": 110, "merge_request": { - "id": 1, + "id": 273, "iid": 1, "project_id": 3, "title": "Test merge train", @@ -47,7 +47,7 @@ } merge_train_update = mr_content.copy() -merge_train_update["id"] = 123 +merge_train_update["iid"] = 4 merge_train_update["pipeline"]["sha"] = "ef33a3zxc3" @@ -69,7 +69,7 @@ def resp_merge_trains_merge_request_get(): with responses.RequestsMock() as rsps: rsps.add( method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_trains/merge_requests/110", + url="http://localhost/api/v4/projects/1/merge_trains/merge_requests/1", json=mr_content, content_type="application/json", status=200, @@ -82,7 +82,7 @@ def resp_merge_trains_merge_request_post(): with responses.RequestsMock() as rsps: rsps.add( method=responses.POST, - url="http://localhost/api/v4/projects/1/merge_trains/merge_requests/123", + url="http://localhost/api/v4/projects/1/merge_trains/merge_requests/4", json=[merge_train_update], content_type="application/json", status=200, @@ -96,24 +96,29 @@ def test_list_project_merge_requests(project, resp_list_merge_trains): assert merge_trains[0].id == mr_content["id"] -def test_merge_trains_status_merge_request_get_status( +def test_merge_trains_status_merge_request( project, resp_merge_trains_merge_request_get ): merge_train_mr: ProjectMergeTrainMergeRequest = project.merge_trains.get( 1, lazy=True - ).merge_requests.get(110) + ).merge_requests.get(1) assert isinstance(merge_train_mr, ProjectMergeTrainMergeRequest) assert merge_train_mr.get_id() == 110 + assert merge_train_mr.merge_request["iid"] == mr_content["merge_request"]["iid"] assert merge_train_mr.pipeline.get("status") == mr_content["pipeline"]["status"] def test_merge_train_add_merge_request(project, resp_merge_trains_merge_request_post): merge_train: ProjectMergeTrain = project.merge_trains.get(1, lazy=True) merge_requests_update = merge_train.merge_requests.update( - 123, new_data={"sha": "ef33a3zxc3"} + 4, new_data={"sha": "ef33a3zxc3"} ) assert isinstance(merge_train, ProjectMergeTrain) assert ( merge_requests_update[0]["pipeline"]["sha"] == merge_train_update["pipeline"]["sha"] ) + assert ( + merge_requests_update[0]["merge_request"]["iid"] + == merge_train_update["merge_request"]["iid"] + ) From d444f049d94dca37f4b29e3e011409a311f18351 Mon Sep 17 00:00:00 2001 From: Isaac Philip <4974658+isaac-philip@users.noreply.github.com> Date: Mon, 3 Mar 2025 00:59:32 +0530 Subject: [PATCH 5/7] feat(functional): #2547 merge-train api for status and add mr - minor changes Signed-off-by: Isaac Philip <4974658+isaac-philip@users.noreply.github.com> --- gitlab/v4/objects/merge_trains.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitlab/v4/objects/merge_trains.py b/gitlab/v4/objects/merge_trains.py index 80469a481..be3fb75ed 100644 --- a/gitlab/v4/objects/merge_trains.py +++ b/gitlab/v4/objects/merge_trains.py @@ -1,5 +1,5 @@ from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import CRUDMixin, GetMixin, ListMixin, UpdateMethod +from gitlab.mixins import GetMixin, ListMixin, UpdateMethod, UpdateMixin from gitlab.types import RequiredOptional __all__ = [ @@ -14,7 +14,7 @@ class ProjectMergeTrainMergeRequest(RESTObject): pass -class ProjectMergeTrainMergeRequestManager(CRUDMixin, RESTManager): +class ProjectMergeTrainMergeRequestManager(GetMixin, UpdateMixin, RESTManager): _path = "/projects/{project_id}/merge_trains/merge_requests" _obj_cls = ProjectMergeTrainMergeRequest _from_parent_attrs = {"project_id": "project_id"} From 60b0ec00ed22be537393e8855b806444a3173134 Mon Sep 17 00:00:00 2001 From: Isaac Philip <4974658+isaac-philip@users.noreply.github.com> Date: Fri, 14 Mar 2025 11:57:17 +0530 Subject: [PATCH 6/7] feat(functional): #2547 merge-train api for status and add mr - lint formatted by black Signed-off-by: Isaac Philip <4974658+isaac-philip@users.noreply.github.com> --- gitlab/v4/objects/merge_trains.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/gitlab/v4/objects/merge_trains.py b/gitlab/v4/objects/merge_trains.py index be3fb75ed..2b483e157 100644 --- a/gitlab/v4/objects/merge_trains.py +++ b/gitlab/v4/objects/merge_trains.py @@ -14,14 +14,18 @@ class ProjectMergeTrainMergeRequest(RESTObject): pass -class ProjectMergeTrainMergeRequestManager(GetMixin, UpdateMixin, RESTManager): +class ProjectMergeTrainMergeRequestManager( + GetMixin[ProjectMergeTrainMergeRequest], + UpdateMixin[ProjectMergeTrainMergeRequest], + RESTManager[ProjectMergeTrainMergeRequest], +): _path = "/projects/{project_id}/merge_trains/merge_requests" _obj_cls = ProjectMergeTrainMergeRequest _from_parent_attrs = {"project_id": "project_id"} _update_method: UpdateMethod = UpdateMethod.POST _update_attrs = RequiredOptional( - optional=("sha", "squash", "when_pipeline_succeeds"), + optional=("sha", "squash", "when_pipeline_succeeds") ) @@ -29,7 +33,11 @@ class ProjectMergeTrain(RESTObject): merge_requests: ProjectMergeTrainMergeRequestManager -class ProjectMergeTrainManager(GetMixin, ListMixin, RESTManager): +class ProjectMergeTrainManager( + GetMixin[ProjectMergeTrain], + ListMixin[ProjectMergeTrain], + RESTManager[ProjectMergeTrain], +): _path = "/projects/{project_id}/merge_trains" _obj_cls = ProjectMergeTrain _from_parent_attrs = {"project_id": "id"} From 3ac656124379b8debff174cdbe7c33a4f33efebd Mon Sep 17 00:00:00 2001 From: Isaac Philip <4974658+isaac-philip@users.noreply.github.com> Date: Fri, 14 Mar 2025 19:18:13 +0530 Subject: [PATCH 7/7] feat(functional): #2547 merge-train api for status and add mr - docs added Signed-off-by: Isaac Philip <4974658+isaac-philip@users.noreply.github.com> --- docs/gl_objects/merge_trains.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/gl_objects/merge_trains.rst b/docs/gl_objects/merge_trains.rst index 6d98e04d8..205053045 100644 --- a/docs/gl_objects/merge_trains.rst +++ b/docs/gl_objects/merge_trains.rst @@ -9,6 +9,8 @@ Reference + :class:`gitlab.v4.objects.ProjectMergeTrain` + :class:`gitlab.v4.objects.ProjectMergeTrainManager` + + :class:`gilab.v4.objects.ProjectMergeTrainMergeRequest` + + :class:`gilab.v4.objects.ProjectMergeTrainMergeRequestManager` + :attr:`gitlab.v4.objects.Project.merge_trains` * GitLab API: https://docs.gitlab.com/api/merge_trains @@ -27,3 +29,13 @@ List active merge trains for a project:: List completed (have been merged) merge trains for a project:: merge_trains = project.merge_trains.list(scope="complete") + +Get Merge Request Status for a Merge Train:: + + merge_train_mr = project.merge_trains.get(1, lazy=True).merge_requests.get(1) + merge_train_mr_status = merge_train_mr.pipeline.get("status") + +Add Merge Request to a Merge Train:: + + merge_train_to_update = project.merge_trains.get(1, lazy=True) + merge_requests_update = merge_train_to_update.merge_requests.update(5, new_data={"sha": "cd22awr721ssds"})