diff --git a/gitlab/v4/objects/__init__.py b/gitlab/v4/objects/__init__.py index 016caece9..c90d18ad5 100644 --- a/gitlab/v4/objects/__init__.py +++ b/gitlab/v4/objects/__init__.py @@ -2996,13 +2996,18 @@ class ProjectMergeRequestApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTMan @exc.on_http_error(exc.GitlabUpdateError) def set_approvers( - self, approvals_required, approver_ids=None, approver_group_ids=None, **kwargs + self, + approvals_required, + approver_ids=None, + approver_group_ids=None, + approval_rule_name="name", + **kwargs ): """Change MR-level allowed approvers and approver groups. Args: approvals_required (integer): The number of required approvals for this rule - approver_ids (list): User IDs that can approve MRs + approver_ids (list of integers): User IDs that can approve MRs approver_group_ids (list): Group IDs whose members can approve MRs Raises: @@ -3012,18 +3017,93 @@ def set_approvers( approver_ids = approver_ids or [] approver_group_ids = approver_group_ids or [] - path = "%s/%s/approval_rules" % ( - self._parent.manager.path, - self._parent.get_id(), - ) data = { - "name": "name", + "name": approval_rule_name, "approvals_required": approvals_required, "rule_type": "regular", "user_ids": approver_ids, "group_ids": approver_group_ids, } - self.gitlab.http_post(path, post_data=data, **kwargs) + approval_rules = self._parent.approval_rules + """ update any existing approval rule matching the name""" + existing_approval_rules = approval_rules.list() + for ar in existing_approval_rules: + if ar.name == approval_rule_name: + ar.user_ids = data["user_ids"] + ar.approvals_required = data["approvals_required"] + ar.group_ids = data["group_ids"] + ar.save() + return + """ if there was no rule matching the rule name, create a new one""" + approval_rules.create(data=data) + + +class ProjectMergeRequestApprovalRule(SaveMixin, RESTObject): + _id_attr = "approval_rule_id" + _short_print_attr = "approval_rule" + + @exc.on_http_error(exc.GitlabUpdateError) + def save(self, **kwargs): + """Save the changes made to the object to the server. + + The object is updated to match what the server returns. + + Args: + **kwargs: Extra options to send to the server (e.g. sudo) + + Raise: + GitlabAuthenticationError: If authentication is not correct + GitlabUpdateError: If the server cannot perform the request + """ + # There is a mismatch between the name of our id attribute and the put REST API name for the + # project_id, so we override it here. + self.approval_rule_id = self.id + self.merge_request_iid = self._parent_attrs["mr_iid"] + self.id = self._parent_attrs["project_id"] + # save will update self.id with the result from the server, so no need to overwrite with + # what it was before we overwrote it.""" + SaveMixin.save(self, **kwargs) + + +class ProjectMergeRequestApprovalRuleManager( + ListMixin, UpdateMixin, CreateMixin, RESTManager +): + _path = "/projects/%(project_id)s/merge_requests/%(mr_iid)s/approval_rules" + _obj_cls = ProjectMergeRequestApprovalRule + _from_parent_attrs = {"project_id": "project_id", "mr_iid": "iid"} + _list_filters = ("name", "rule_type") + _update_attrs = ( + ("id", "merge_request_iid", "approval_rule_id", "name", "approvals_required"), + ("user_ids", "group_ids"), + ) + # Important: When approval_project_rule_id is set, the name, users and groups of + # project-level rule will be copied. The approvals_required specified will be used. """ + _create_attrs = ( + ("id", "merge_request_iid", "name", "approvals_required"), + ("approval_project_rule_id", "user_ids", "group_ids"), + ) + + def create(self, data, **kwargs): + """Create a new object. + + Args: + data (dict): Parameters to send to the server to create the + resource + **kwargs: Extra options to send to the server (e.g. sudo or + 'ref_name', 'stage', 'name', 'all') + + Raises: + GitlabAuthenticationError: If authentication is not correct + GitlabCreateError: If the server cannot perform the request + + Returns: + RESTObject: A new instance of the manage object class build with + the data sent by the server + """ + new_data = data.copy() + new_data["id"] = self._from_parent_attrs["project_id"] + new_data["merge_request_iid"] = self._from_parent_attrs["mr_iid"] + return CreateMixin.create(self, new_data, **kwargs) class ProjectMergeRequestAwardEmoji(ObjectDeleteMixin, RESTObject): @@ -3149,6 +3229,7 @@ class ProjectMergeRequest( _managers = ( ("approvals", "ProjectMergeRequestApprovalManager"), + ("approval_rules", "ProjectMergeRequestApprovalRuleManager"), ("awardemojis", "ProjectMergeRequestAwardEmojiManager"), ("diffs", "ProjectMergeRequestDiffManager"), ("discussions", "ProjectMergeRequestDiscussionManager"),