Skip to content

Commit 768890a

Browse files
authored
Merge pull request #1266 from gokeefe/gokeefe/group_push_rules
#1259 Add GroupPushRules and GroupPushRulesManager classes
2 parents 3df404c + b5cdc09 commit 768890a

File tree

4 files changed

+194
-2
lines changed

4 files changed

+194
-2
lines changed

docs/gl_objects/groups.rst

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,3 +376,37 @@ Delete a group hook::
376376
group.hooks.delete(hook_id)
377377
# or
378378
hook.delete()
379+
380+
Group push rules
381+
==================
382+
383+
Reference
384+
---------
385+
386+
* v4 API:
387+
388+
+ :class:`gitlab.v4.objects.GroupPushRules`
389+
+ :class:`gitlab.v4.objects.GroupPushRulesManager`
390+
+ :attr:`gitlab.v4.objects.Group.pushrules`
391+
392+
* GitLab API: https://docs.gitlab.com/ee/api/groups.html#push-rules
393+
394+
Examples
395+
---------
396+
397+
Create group push rules (at least one rule is necessary)::
398+
399+
group.pushrules.create({'deny_delete_tag': True})
400+
401+
Get group push rules (returns None is there are no push rules)::
402+
403+
pr = group.pushrules.get()
404+
405+
Edit group push rules::
406+
407+
pr.branch_name_regex = '^(master|develop|support-\d+|release-\d+\..+|hotfix-.+|feature-.+)$'
408+
pr.save()
409+
410+
Delete group push rules::
411+
412+
pr.delete()

gitlab/v4/objects/groups.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from .notification_settings import GroupNotificationSettingsManager # noqa: F401
3434
from .packages import GroupPackageManager # noqa: F401
3535
from .projects import GroupProjectManager # noqa: F401
36+
from .push_rules import GroupPushRulesManager
3637
from .runners import GroupRunnerManager # noqa: F401
3738
from .statistics import GroupIssuesStatisticsManager # noqa: F401
3839
from .variables import GroupVariableManager # noqa: F401
@@ -75,6 +76,7 @@ class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
7576
notificationsettings: GroupNotificationSettingsManager
7677
packages: GroupPackageManager
7778
projects: GroupProjectManager
79+
pushrules: GroupPushRulesManager
7880
runners: GroupRunnerManager
7981
subgroups: "GroupSubgroupManager"
8082
variables: GroupVariableManager

gitlab/v4/objects/push_rules.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
from gitlab.types import RequiredOptional
1313

1414
__all__ = [
15+
"GroupPushRules",
16+
"GroupPushRulesManager",
1517
"ProjectPushRules",
1618
"ProjectPushRulesManager",
1719
]
@@ -27,16 +29,64 @@ class ProjectPushRulesManager(
2729
_path = "/projects/{project_id}/push_rule"
2830
_obj_cls = ProjectPushRules
2931
_from_parent_attrs = {"project_id": "id"}
32+
_create_attrs = RequiredOptional(
33+
optional=(
34+
"author_email_regex",
35+
"branch_name_regex",
36+
"commit_committer_check",
37+
"commit_message_negative_regex",
38+
"commit_message_regex",
39+
"deny_delete_tag",
40+
"file_name_regex",
41+
"max_file_size",
42+
"member_check",
43+
"prevent_secrets",
44+
"reject_unsigned_commits",
45+
),
46+
)
47+
_update_attrs = RequiredOptional(
48+
optional=(
49+
"author_email_regex",
50+
"branch_name_regex",
51+
"commit_committer_check",
52+
"commit_message_negative_regex",
53+
"commit_message_regex",
54+
"deny_delete_tag",
55+
"file_name_regex",
56+
"max_file_size",
57+
"member_check",
58+
"prevent_secrets",
59+
"reject_unsigned_commits",
60+
),
61+
)
62+
63+
def get(self, **kwargs: Any) -> ProjectPushRules:
64+
return cast(ProjectPushRules, super().get(**kwargs))
65+
66+
67+
class GroupPushRules(SaveMixin, ObjectDeleteMixin, RESTObject):
68+
_id_attr = None
69+
70+
71+
class GroupPushRulesManager(
72+
GetWithoutIdMixin, CreateMixin, UpdateMixin, DeleteMixin, RESTManager
73+
):
74+
_path = "/groups/{group_id}/push_rule"
75+
_obj_cls = GroupPushRules
76+
_from_parent_attrs = {"group_id": "id"}
3077
_create_attrs = RequiredOptional(
3178
optional=(
3279
"deny_delete_tag",
3380
"member_check",
3481
"prevent_secrets",
3582
"commit_message_regex",
83+
"commit_message_negative_regex",
3684
"branch_name_regex",
3785
"author_email_regex",
3886
"file_name_regex",
3987
"max_file_size",
88+
"commit_committer_check",
89+
"reject_unsigned_commits",
4090
),
4191
)
4292
_update_attrs = RequiredOptional(
@@ -45,12 +95,15 @@ class ProjectPushRulesManager(
4595
"member_check",
4696
"prevent_secrets",
4797
"commit_message_regex",
98+
"commit_message_negative_regex",
4899
"branch_name_regex",
49100
"author_email_regex",
50101
"file_name_regex",
51102
"max_file_size",
103+
"commit_committer_check",
104+
"reject_unsigned_commits",
52105
),
53106
)
54107

55-
def get(self, **kwargs: Any) -> ProjectPushRules:
56-
return cast(ProjectPushRules, super().get(**kwargs))
108+
def get(self, **kwargs: Any) -> GroupPushRules:
109+
return cast(GroupPushRules, super().get(**kwargs))

tests/unit/objects/test_groups.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@
3838
"created_at": "2020-01-15T12:36:29.590Z",
3939
},
4040
]
41+
push_rules_content = {
42+
"id": 2,
43+
"created_at": "2020-08-17T19:09:19.580Z",
44+
"commit_message_regex": "[a-zA-Z]",
45+
"commit_message_negative_regex": "[x+]",
46+
"branch_name_regex": "[a-z]",
47+
"deny_delete_tag": True,
48+
"member_check": True,
49+
"prevent_secrets": True,
50+
"author_email_regex": "^[A-Za-z0-9.]+@gitlab.com$",
51+
"file_name_regex": "(exe)$",
52+
"max_file_size": 100,
53+
}
4154

4255

4356
@pytest.fixture
@@ -111,6 +124,72 @@ def resp_transfer_group():
111124
yield rsps
112125

113126

127+
@pytest.fixture
128+
def resp_list_push_rules_group():
129+
with responses.RequestsMock() as rsps:
130+
rsps.add(
131+
method=responses.GET,
132+
url="http://localhost/api/v4/groups/1/push_rule",
133+
json=push_rules_content,
134+
content_type="application/json",
135+
status=200,
136+
)
137+
yield rsps
138+
139+
140+
@pytest.fixture
141+
def resp_create_push_rules_group():
142+
with responses.RequestsMock() as rsps:
143+
rsps.add(
144+
method=responses.POST,
145+
url="http://localhost/api/v4/groups/1/push_rule",
146+
json=push_rules_content,
147+
content_type="application/json",
148+
status=201,
149+
)
150+
yield rsps
151+
152+
153+
@pytest.fixture
154+
def resp_update_push_rules_group():
155+
with responses.RequestsMock() as rsps:
156+
rsps.add(
157+
method=responses.GET,
158+
url="http://localhost/api/v4/groups/1/push_rule",
159+
json=push_rules_content,
160+
content_type="application/json",
161+
status=200,
162+
)
163+
rsps.add(
164+
method=responses.PUT,
165+
url="http://localhost/api/v4/groups/1/push_rule",
166+
json=push_rules_content,
167+
content_type="application/json",
168+
status=201,
169+
)
170+
yield rsps
171+
172+
173+
@pytest.fixture
174+
def resp_delete_push_rules_group(no_content):
175+
with responses.RequestsMock() as rsps:
176+
rsps.add(
177+
method=responses.GET,
178+
url="http://localhost/api/v4/groups/1/push_rule",
179+
json=push_rules_content,
180+
content_type="application/json",
181+
status=200,
182+
)
183+
rsps.add(
184+
method=responses.DELETE,
185+
url="http://localhost/api/v4/groups/1/push_rule",
186+
json=no_content,
187+
content_type="application/json",
188+
status=204,
189+
)
190+
yield rsps
191+
192+
114193
def test_get_group(gl, resp_groups):
115194
data = gl.groups.get(1)
116195
assert isinstance(data, gitlab.v4.objects.Group)
@@ -173,3 +252,27 @@ def test_refresh_group_import_status(group, resp_groups):
173252
def test_transfer_group(gl, resp_transfer_group):
174253
group = gl.groups.get(1, lazy=True)
175254
group.transfer("test-namespace")
255+
256+
257+
def test_list_group_push_rules(group, resp_list_push_rules_group):
258+
pr = group.pushrules.get()
259+
assert pr
260+
assert pr.deny_delete_tag
261+
262+
263+
def test_create_group_push_rule(group, resp_create_push_rules_group):
264+
group.pushrules.create({"deny_delete_tag": True})
265+
266+
267+
def test_update_group_push_rule(
268+
group,
269+
resp_update_push_rules_group,
270+
):
271+
pr = group.pushrules.get()
272+
pr.deny_delete_tag = False
273+
pr.save()
274+
275+
276+
def test_delete_group_push_rule(group, resp_delete_push_rules_group):
277+
pr = group.pushrules.get()
278+
pr.delete()

0 commit comments

Comments
 (0)