Skip to content

Commit 59a19ca

Browse files
author
Gauvain Pocentek
committed
Implement MR-level approvals
Fixes #323
1 parent 8df6de9 commit 59a19ca

File tree

3 files changed

+77
-19
lines changed

3 files changed

+77
-19
lines changed

docs/gl_objects/mr_approvals.rst

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
##############################################
2-
Project-level merge request approvals settings
3-
##############################################
1+
################################
2+
Merge request approvals settings
3+
################################
4+
5+
Merge request approvals can be defined at the project level or at the merge
6+
request level.
47

58
References
69
----------
@@ -10,21 +13,33 @@ References
1013
+ :class:`gitlab.v4.objects.ProjectApproval`
1114
+ :class:`gitlab.v4.objects.ProjectApprovalManager`
1215
+ :attr:`gitlab.v4.objects.Project.approvals`
16+
+ :class:`gitlab.v4.objects.ProjectMergeRequestApproval`
17+
+ :class:`gitlab.v4.objects.ProjectMergeRequestApprovalManager`
18+
+ :attr:`gitlab.v4.objects.ProjectMergeRequest.approvals`
1319

14-
* GitLab API: https://docs.gitlab.com/ee/api/merge_request_approvals.html#project-level-mr-approvals
20+
* GitLab API: https://docs.gitlab.com/ee/api/merge_request_approvals.html
1521

1622
Examples
1723
--------
1824

19-
Get project-level MR approvals settings::
25+
Get project-level or MR-level MR approvals settings::
26+
27+
p_mras = project.approvals.get()
28+
29+
mr_mras = mr.approvals.get()
30+
31+
Change project-level or MR-level MR approvals settings::
2032

21-
mras = project.approvals.get()
33+
p_mras.approvals_before_merge = 2
34+
p_mras.save()
2235

23-
Change project-level MR approvals settings::
36+
mr_mras.approvals_before_merge = 2
37+
mr_mras.save()
2438

25-
mras.approvals_before_merge = 2
26-
mras.save()
39+
Change project-level or MR-level MR allowed approvers::
2740

28-
Change project-level MR allowed approvers::
41+
project.approvals.set_approvers(approver_ids=[105],
42+
approver_group_ids=[653, 654])
2943

30-
project.approvals.set_approvers(approver_ids = [105], approver_group_ids=[653, 654])
44+
mr.approvals.set_approvers(approver_ids=[105],
45+
approver_group_ids=[653, 654])

gitlab/v4/objects.py

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,6 +1795,37 @@ class ProjectTagManager(NoUpdateMixin, RESTManager):
17951795
_create_attrs = (('tag_name', 'ref'), ('message',))
17961796

17971797

1798+
class ProjectMergeRequestApproval(SaveMixin, RESTObject):
1799+
_id_attr = None
1800+
1801+
1802+
class ProjectMergeRequestApprovalManager(GetWithoutIdMixin, UpdateMixin,
1803+
RESTManager):
1804+
_path = '/projects/%(project_id)s/merge_requests/%(mr_iid)s/approvals'
1805+
_obj_cls = ProjectMergeRequestApproval
1806+
_from_parent_attrs = {'project_id': 'project_id', 'mr_iid': 'iid'}
1807+
_update_attrs = (('approvals_required',), tuple())
1808+
_update_uses_post = True
1809+
1810+
@exc.on_http_error(exc.GitlabUpdateError)
1811+
def set_approvers(self, approver_ids=[], approver_group_ids=[], **kwargs):
1812+
"""Change MR-level allowed approvers and approver groups.
1813+
1814+
Args:
1815+
approver_ids (list): User IDs that can approve MRs
1816+
approver_group_ids (list): Group IDs whose members can approve MRs
1817+
1818+
Raises:
1819+
GitlabAuthenticationError: If authentication is not correct
1820+
GitlabUpdateError: If the server failed to perform the request
1821+
"""
1822+
path = '%s/%s/approvers' % (self._parent.manager.path,
1823+
self._parent.get_id())
1824+
data = {'approver_ids': approver_ids,
1825+
'approver_group_ids': approver_group_ids}
1826+
self.gitlab.http_put(path, post_data=data, **kwargs)
1827+
1828+
17981829
class ProjectMergeRequestAwardEmoji(ObjectDeleteMixin, RESTObject):
17991830
pass
18001831

@@ -1879,6 +1910,7 @@ class ProjectMergeRequest(SubscribableMixin, TodoMixin, TimeTrackingMixin,
18791910
_id_attr = 'iid'
18801911

18811912
_managers = (
1913+
('approvals', 'ProjectMergeRequestApprovalManager'),
18821914
('awardemojis', 'ProjectMergeRequestAwardEmojiManager'),
18831915
('diffs', 'ProjectMergeRequestDiffManager'),
18841916
('discussions', 'ProjectMergeRequestDiscussionManager'),
@@ -2761,13 +2793,12 @@ class ProjectApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTManager):
27612793
_update_uses_post = True
27622794

27632795
@exc.on_http_error(exc.GitlabUpdateError)
2764-
def set_approvers(self, approver_ids=[], approver_group_ids=[],
2765-
**kwargs):
2796+
def set_approvers(self, approver_ids=[], approver_group_ids=[], **kwargs):
27662797
"""Change project-level allowed approvers and approver groups.
27672798
27682799
Args:
2769-
approver_ids (list): User IDs that can approve MRs.
2770-
approver_group_ids (list): Group IDs whose members can approve MRs.
2800+
approver_ids (list): User IDs that can approve MRs
2801+
approver_group_ids (list): Group IDs whose members can approve MRs
27712802
27722803
Raises:
27732804
GitlabAuthenticationError: If authentication is not correct
@@ -2777,10 +2808,7 @@ def set_approvers(self, approver_ids=[], approver_group_ids=[],
27772808
path = '/projects/%s/approvers' % self._parent.get_id()
27782809
data = {'approver_ids': approver_ids,
27792810
'approver_group_ids': approver_group_ids}
2780-
try:
2781-
self.gitlab.http_put(path, post_data=data, **kwargs)
2782-
except exc.GitlabHttpError as e:
2783-
raise exc.GitlabUpdateError(e.response_code, e.error_message)
2811+
self.gitlab.http_put(path, post_data=data, **kwargs)
27842812

27852813

27862814
class ProjectDeployment(RESTObject):

tools/ee-test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
P1 = 'root/project1'
77
P2 = 'root/project2'
8+
MR_P1 = 1
89
I_P1 = 1
910
I_P2 = 1
1011
G1 = 'group1'
@@ -26,6 +27,7 @@ def end_log():
2627
issue_p1 = project1.issues.get(I_P1)
2728
issue_p2 = project2.issues.get(I_P2)
2829
group1 = gl.groups.get(G1)
30+
mr = project1.mergerequests.get(1)
2931

3032
start_log('MR approvals')
3133
approval = project1.approvals.get()
@@ -37,6 +39,19 @@ def end_log():
3739
project1.approvals.set_approvers([1], [])
3840
approval = project1.approvals.get()
3941
assert(approval.approvers[0]['user']['id'] == 1)
42+
43+
approval = mr.approvals.get()
44+
approval.approvals_required = 2
45+
approval.save()
46+
approval = mr.approvals.get()
47+
assert(approval.approvals_required == 2)
48+
approval.approvals_required = 3
49+
approval.save()
50+
approval = mr.approvals.get()
51+
assert(approval.approvals_required == 3)
52+
mr.approvals.set_approvers([1], [])
53+
approval = mr.approvals.get()
54+
assert(approval.approvers[0]['user']['id'] == 1)
4055
end_log()
4156

4257
start_log('geo nodes')

0 commit comments

Comments
 (0)