@@ -2996,13 +2996,18 @@ class ProjectMergeRequestApprovalManager(GetWithoutIdMixin, UpdateMixin, RESTMan
29962996
29972997@exc .on_http_error (exc .GitlabUpdateError )
29982998def 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(
30123017approver_ids = approver_ids or []
30133018approver_group_ids = approver_group_ids or []
30143019
3015- path = "%s/%s/approval_rules" % (
3016- self ._parent .manager .path ,
3017- self ._parent .get_id (),
3018- )
30193020data = {
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
30293109class 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" ),