Skip to content

Commit c6fbf39

Browse files
committed
feat: adds support for project merge request approval rules (#1199)
1 parent 266030a commit c6fbf39

File tree

1 file changed

+89
-8
lines changed

1 file changed

+89
-8
lines changed

gitlab/v4/objects/__init__.py

Lines changed: 89 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2996,13 +2996,18 @@ class ProjectMergeRequestApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTMan
29962996

29972997
@exc.on_http_error(exc.GitlabUpdateError)
29982998
def set_approvers(
2999-
self, approvals_required, approver_ids=None, approver_group_ids=None, **kwargs
2999+
self,
3000+
approvals_required,
3001+
approver_ids=None,
3002+
approver_group_ids=None,
3003+
approval_rule_name="name",
3004+
**kwargs
30003005
):
30013006
"""Change MR-level allowed approvers and approver groups.
30023007
30033008
Args:
30043009
approvals_required (integer): The number of required approvals for this rule
3005-
approver_ids (list): User IDs that can approve MRs
3010+
approver_ids (list of integers): User IDs that can approve MRs
30063011
approver_group_ids (list): Group IDs whose members can approve MRs
30073012
30083013
Raises:
@@ -3012,18 +3017,93 @@ def set_approvers(
30123017
approver_ids = approver_ids or []
30133018
approver_group_ids = approver_group_ids or []
30143019

3015-
path = "%s/%s/approval_rules" % (
3016-
self._parent.manager.path,
3017-
self._parent.get_id(),
3018-
)
30193020
data = {
3020-
"name": "name",
3021+
"name": approval_rule_name,
30213022
"approvals_required": approvals_required,
30223023
"rule_type": "regular",
30233024
"user_ids": approver_ids,
30243025
"group_ids": approver_group_ids,
30253026
}
3026-
self.gitlab.http_post(path, post_data=data, **kwargs)
3027+
approval_rules = self._parent.approval_rules
3028+
""" update any existing approval rule matching the name"""
3029+
existing_approval_rules = approval_rules.list()
3030+
for ar in existing_approval_rules:
3031+
if ar.name == approval_rule_name:
3032+
ar.user_ids = data["user_ids"]
3033+
ar.approvals_required = data["approvals_required"]
3034+
ar.group_ids = data["group_ids"]
3035+
ar.save()
3036+
return
3037+
""" if there was no rule matching the rule name, create a new one"""
3038+
approval_rules.create(data=data)
3039+
3040+
3041+
class ProjectMergeRequestApprovalRule(SaveMixin, RESTObject):
3042+
_id_attr = "approval_rule_id"
3043+
_short_print_attr = "approval_rule"
3044+
3045+
@exc.on_http_error(exc.GitlabUpdateError)
3046+
def save(self, **kwargs):
3047+
"""Save the changes made to the object to the server.
3048+
3049+
The object is updated to match what the server returns.
3050+
3051+
Args:
3052+
**kwargs: Extra options to send to the server (e.g. sudo)
3053+
3054+
Raise:
3055+
GitlabAuthenticationError: If authentication is not correct
3056+
GitlabUpdateError: If the server cannot perform the request
3057+
"""
3058+
# There is a mismatch between the name of our id attribute and the put REST API name for the
3059+
# project_id, so we override it here.
3060+
self.approval_rule_id = self.id
3061+
self.merge_request_iid = self._parent_attrs["mr_iid"]
3062+
self.id = self._parent_attrs["project_id"]
3063+
# save will update self.id with the result from the server, so no need to overwrite with
3064+
# what it was before we overwrote it."""
3065+
SaveMixin.save(self, **kwargs)
3066+
3067+
3068+
class ProjectMergeRequestApprovalRuleManager(
3069+
ListMixin, UpdateMixin, CreateMixin, RESTManager
3070+
):
3071+
_path = "/projects/%(project_id)s/merge_requests/%(mr_iid)s/approval_rules"
3072+
_obj_cls = ProjectMergeRequestApprovalRule
3073+
_from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"}
3074+
_list_filters = ("name", "rule_type")
3075+
_update_attrs = (
3076+
("id", "merge_request_iid", "approval_rule_id", "name", "approvals_required"),
3077+
("user_ids", "group_ids"),
3078+
)
3079+
# Important: When approval_project_rule_id is set, the name, users and groups of
3080+
# project-level rule will be copied. The approvals_required specified will be used. """
3081+
_create_attrs = (
3082+
("id", "merge_request_iid", "name", "approvals_required"),
3083+
("approval_project_rule_id", "user_ids", "group_ids"),
3084+
)
3085+
3086+
def create(self, data, **kwargs):
3087+
"""Create a new object.
3088+
3089+
Args:
3090+
data (dict): Parameters to send to the server to create the
3091+
resource
3092+
**kwargs: Extra options to send to the server (e.g. sudo or
3093+
'ref_name', 'stage', 'name', 'all')
3094+
3095+
Raises:
3096+
GitlabAuthenticationError: If authentication is not correct
3097+
GitlabCreateError: If the server cannot perform the request
3098+
3099+
Returns:
3100+
RESTObject: A new instance of the manage object class build with
3101+
the data sent by the server
3102+
"""
3103+
new_data = data.copy()
3104+
new_data["id"] = self._from_parent_attrs["project_id"]
3105+
new_data["merge_request_iid"] = self._from_parent_attrs["mr_iid"]
3106+
return CreateMixin.create(self, new_data, **kwargs)
30273107

30283108

30293109
class ProjectMergeRequestAwardEmoji(ObjectDeleteMixin, RESTObject):
@@ -3149,6 +3229,7 @@ class ProjectMergeRequest(
31493229

31503230
_managers = (
31513231
("approvals", "ProjectMergeRequestApprovalManager"),
3232+
("approval_rules", "ProjectMergeRequestApprovalRuleManager"),
31523233
("awardemojis", "ProjectMergeRequestAwardEmojiManager"),
31533234
("diffs", "ProjectMergeRequestDiffManager"),
31543235
("discussions", "ProjectMergeRequestDiscussionManager"),

0 commit comments

Comments
 (0)