Skip to content

Commit e77554c

Browse files
Merge pull request #1323 from python-gitlab/feat/mr-pipeline-manager
feat(api): add merge request pipeline manager and deprecate mr.pipelines() method
2 parents 1f5b3c0 + 954357c commit e77554c

File tree

5 files changed

+134
-24
lines changed

5 files changed

+134
-24
lines changed

docs/gl_objects/mrs.rst

+25-4
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,6 @@ List the changes of a MR::
127127

128128
changes = mr.changes()
129129

130-
List the pipelines for a MR::
131-
132-
pipelines = mr.pipelines()
133-
134130
List issues that will close on merge::
135131

136132
mr.closes_issues()
@@ -185,3 +181,28 @@ Get user agent detail for the issue (admin only)::
185181
Attempt to rebase an MR::
186182

187183
mr.rebase()
184+
185+
Merge Request Pipelines
186+
=======================
187+
188+
Reference
189+
---------
190+
191+
* v4 API:
192+
193+
+ :class:`gitlab.v4.objects.ProjectMergeRequestPipeline`
194+
+ :class:`gitlab.v4.objects.ProjectMergeRequestPipelineManager`
195+
+ :attr:`gitlab.v4.objects.ProjectMergeRequest.pipelines`
196+
197+
* GitLab API: https://docs.gitlab.com/ee/api/merge_requests.html#list-mr-pipelines
198+
199+
Examples
200+
--------
201+
202+
List pipelines for a merge request::
203+
204+
pipelines = mr.pipelines.list()
205+
206+
Create a pipeline for a merge request::
207+
208+
pipeline = mr.pipelines.create()

gitlab/cli.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def register_custom_action(
5353
cls_names: Union[str, Tuple[str, ...]],
5454
mandatory: Tuple[str, ...] = tuple(),
5555
optional: Tuple[str, ...] = tuple(),
56+
custom_action: Optional[str] = None,
5657
) -> Callable[[__F], __F]:
5758
def wrap(f: __F) -> __F:
5859
@functools.wraps(f)
@@ -74,7 +75,7 @@ def wrapped_f(*args: Any, **kwargs: Any) -> Any:
7475
if final_name not in custom_actions:
7576
custom_actions[final_name] = {}
7677

77-
action = f.__name__.replace("_", "-")
78+
action = custom_action or f.__name__.replace("_", "-")
7879
custom_actions[final_name][action] = (mandatory, optional, in_obj)
7980

8081
return cast(__F, wrapped_f)

gitlab/v4/objects/merge_requests.py

+2-19
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
ProjectMergeRequestApprovalRuleManager,
2929
)
3030
from .notes import ProjectMergeRequestNoteManager # noqa: F401
31+
from .pipelines import ProjectMergeRequestPipelineManager # noqa: F401
3132

3233
__all__ = [
3334
"MergeRequest",
@@ -145,6 +146,7 @@ class ProjectMergeRequest(
145146
("diffs", "ProjectMergeRequestDiffManager"),
146147
("discussions", "ProjectMergeRequestDiscussionManager"),
147148
("notes", "ProjectMergeRequestNoteManager"),
149+
("pipelines", "ProjectMergeRequestPipelineManager"),
148150
("resourcelabelevents", "ProjectMergeRequestResourceLabelEventManager"),
149151
("resourcemilestoneevents", "ProjectMergeRequestResourceMilestoneEventManager"),
150152
("resourcestateevents", "ProjectMergeRequestResourceStateEventManager"),
@@ -240,25 +242,6 @@ def changes(self, **kwargs):
240242
path = "%s/%s/changes" % (self.manager.path, self.get_id())
241243
return self.manager.gitlab.http_get(path, **kwargs)
242244

243-
@cli.register_custom_action("ProjectMergeRequest")
244-
@exc.on_http_error(exc.GitlabListError)
245-
def pipelines(self, **kwargs):
246-
"""List the merge request pipelines.
247-
248-
Args:
249-
**kwargs: Extra options to send to the server (e.g. sudo)
250-
251-
Raises:
252-
GitlabAuthenticationError: If authentication is not correct
253-
GitlabListError: If the list could not be retrieved
254-
255-
Returns:
256-
RESTObjectList: List of changes
257-
"""
258-
259-
path = "%s/%s/pipelines" % (self.manager.path, self.get_id())
260-
return self.manager.gitlab.http_get(path, **kwargs)
261-
262245
@cli.register_custom_action("ProjectMergeRequest", tuple(), ("sha",))
263246
@exc.on_http_error(exc.GitlabMRApprovalError)
264247
def approve(self, sha=None, **kwargs):

gitlab/v4/objects/pipelines.py

+41
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import warnings
2+
13
from gitlab import cli
24
from gitlab import exceptions as exc
35
from gitlab.base import RequiredOptional, RESTManager, RESTObject
@@ -15,6 +17,8 @@
1517
)
1618

1719
__all__ = [
20+
"ProjectMergeRequestPipeline",
21+
"ProjectMergeRequestPipelineManager",
1822
"ProjectPipeline",
1923
"ProjectPipelineManager",
2024
"ProjectPipelineJob",
@@ -32,6 +36,43 @@
3236
]
3337

3438

39+
class ProjectMergeRequestPipeline(RESTObject):
40+
pass
41+
42+
43+
class ProjectMergeRequestPipelineManager(CreateMixin, ListMixin, RESTManager):
44+
_path = "/projects/%(project_id)s/merge_requests/%(mr_iid)s/pipelines"
45+
_obj_cls = ProjectMergeRequestPipeline
46+
_from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"}
47+
48+
# If the manager was called directly as a callable via
49+
# mr.pipelines(), execute the deprecated method for now.
50+
# TODO: in python-gitlab 3.0.0, remove this method entirely.
51+
52+
@cli.register_custom_action("ProjectMergeRequest", custom_action="pipelines")
53+
@exc.on_http_error(exc.GitlabListError)
54+
def __call__(self, **kwargs):
55+
"""List the merge request pipelines.
56+
57+
Args:
58+
**kwargs: Extra options to send to the server (e.g. sudo)
59+
60+
Raises:
61+
GitlabAuthenticationError: If authentication is not correct
62+
GitlabListError: If the list could not be retrieved
63+
64+
Returns:
65+
RESTObjectList: List of changes
66+
"""
67+
warnings.warn(
68+
"Calling the ProjectMergeRequest.pipelines() method on "
69+
"merge request objects directly is deprecated and will be replaced "
70+
"by ProjectMergeRequest.pipelines.list() in python-gitlab 3.0.0.\n",
71+
DeprecationWarning,
72+
)
73+
return self.list(**kwargs)
74+
75+
3576
class ProjectPipeline(RefreshMixin, ObjectDeleteMixin, RESTObject):
3677
_managers = (
3778
("jobs", "ProjectPipelineJobManager"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""
2+
GitLab API: https://docs.gitlab.com/ee/api/merge_requests.html#list-mr-pipelines
3+
"""
4+
import pytest
5+
import responses
6+
7+
from gitlab.v4.objects import ProjectMergeRequestPipeline
8+
9+
pipeline_content = {
10+
"id": 1,
11+
"sha": "959e04d7c7a30600c894bd3c0cd0e1ce7f42c11d",
12+
"ref": "master",
13+
"status": "success",
14+
}
15+
16+
17+
@pytest.fixture()
18+
def resp_list_merge_request_pipelines():
19+
with responses.RequestsMock() as rsps:
20+
rsps.add(
21+
method=responses.GET,
22+
url="http://localhost/api/v4/projects/1/merge_requests/1/pipelines",
23+
json=[pipeline_content],
24+
content_type="application/json",
25+
status=200,
26+
)
27+
yield rsps
28+
29+
30+
@pytest.fixture()
31+
def resp_create_merge_request_pipeline():
32+
with responses.RequestsMock() as rsps:
33+
rsps.add(
34+
method=responses.POST,
35+
url="http://localhost/api/v4/projects/1/merge_requests/1/pipelines",
36+
json=pipeline_content,
37+
content_type="application/json",
38+
status=201,
39+
)
40+
yield rsps
41+
42+
43+
def test_merge_requests_pipelines_deprecated_raises_warning(
44+
project, resp_list_merge_request_pipelines
45+
):
46+
with pytest.deprecated_call():
47+
pipelines = project.mergerequests.get(1, lazy=True).pipelines()
48+
49+
assert len(pipelines) == 1
50+
assert isinstance(pipelines[0], ProjectMergeRequestPipeline)
51+
assert pipelines[0].sha == pipeline_content["sha"]
52+
53+
54+
def test_list_merge_requests_pipelines(project, resp_list_merge_request_pipelines):
55+
pipelines = project.mergerequests.get(1, lazy=True).pipelines.list()
56+
assert len(pipelines) == 1
57+
assert isinstance(pipelines[0], ProjectMergeRequestPipeline)
58+
assert pipelines[0].sha == pipeline_content["sha"]
59+
60+
61+
def test_create_merge_requests_pipelines(project, resp_create_merge_request_pipeline):
62+
pipeline = project.mergerequests.get(1, lazy=True).pipelines.create()
63+
assert isinstance(pipeline, ProjectMergeRequestPipeline)
64+
assert pipeline.sha == pipeline_content["sha"]

0 commit comments

Comments
 (0)