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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy