8000 feat(api): add support for package protection rules · python-gitlab/python-gitlab@6b37811 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6b37811

Browse files
nejchJohnVillalovos
authored andcommitted
feat(api): add support for package protection rules
1 parent c378817 commit 6b37811

File tree

7 files changed

+214
-1
lines changed

7 files changed

+214
-1
lines changed

docs/api-objects.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ API examples
4949
gl_objects/project_access_tokens
5050
gl_objects/protected_branches
5151
gl_objects/protected_environments
52+
gl_objects/protected_packages
5253
gl_objects/releases
5354
gl_objects/runners
5455
gl_objects/remote_mirrors
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
##################
2+
Protected packages
3+
##################
4+
5+
You can list and manage package protection rules in a project.
6+
7+
References
8+
----------
9+
10+
* v4 API:
11+
12+
+ :class:`gitlab.v4.objects.ProjectPackageProtectionRule`
13+
+ :class:`gitlab.v4.objects.ProjectPackageProtectionRuleManager`
14+
+ :attr:`gitlab.v4.objects.Project.package_protection_rules`
15+
16+
* GitLab API: https://docs.gitlab.com/ee/api/project_packages_protection_rules.html
17+
18+
Examples
19+
--------
20+
21+
List the package protection rules for a project::
22+
23+
package_rules = project.package_protection_rules.list()
24+
25+
Create a package protection rule::
26+
27+
package_rule = project.package_protection_rules.create(
28+
{
29+
'package_name_pattern': 'v*',
30+
'package_type': 'npm',
31+
'minimum_access_level_for_push': 'maintainer'
32+
}
33+
)
34+
35+
Update a package protection rule::
36+
37+
package_rule.minimum_access_level_for_push = 'developer'
38+
package_rule.save()
39+
40+
Delete a package protection rule::
41+
42+
package_rule = project.package_protection_rules.delete(package_rule.id)
43+
# or
44+
package_rule.delete()

gitlab/v4/objects/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
from .namespaces import *
4747
from .notes import *
4848
from .notification_settings import *
49+
from .package_protection_rules import *
4950
from .packages import *
5051
from .pages import *
5152
from .personal_access_tokens import *
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from gitlab.base import RESTManager, RESTObject
2+
from gitlab.mixins import (
3+
CreateMixin,
4+
DeleteMixin,
5+
ListMixin,
6+
ObjectDeleteMixin,
7+
SaveMixin,
8+
UpdateMethod,
9+
UpdateMixin,
10+
)
11+
from gitlab.types import RequiredOptional
12+
13+
__all__ = [
14+
"ProjectPackageProtectionRule",
15+
"ProjectPackageProtectionRuleManager",
16+
]
17+
18+
19+
class ProjectPackageProtectionRule(ObjectDeleteMixin, SaveMixin, RESTObject):
20+
_repr_attr = "name"
21+
22+
23+
class ProjectPackageProtectionRuleManager(
24+
ListMixin, CreateMixin, DeleteMixin, UpdateMixin, RESTManager
25+
):
26+
_path = "/projects/{project_id}/packages/protection/rules"
27+
_obj_cls = ProjectPackageProtectionRule
28+
_from_parent_attrs = {"project_id": "id"}
29+
_create_attrs = RequiredOptional(
30+
required=(
31+
"package_name_pattern",
32+
"package_type",
33+
"minimum_access_level_for_push",
34+
),
35+
)
36+
_update_method = UpdateMethod.PATCH

gitlab/v4/objects/projects.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
from .milestones import ProjectMilestoneManager # noqa: F401
7676
from .notes import ProjectNoteManager # noqa: F401
7777
from .notification_settings import ProjectNotificationSettingsManager # noqa: F401
78+
from .package_protection_rules import ProjectPackageProtectionRuleManager
7879
from .packages import GenericPackageManager, ProjectPackageManager # noqa: F401
7980
from .pages import ProjectPagesDomainManager # noqa: F401
8081
from .pipelines import ( # noqa: F401
@@ -209,6 +210,7 @@ class Project(
209210
notes: ProjectNoteManager
210211
notificationsettings: ProjectNotificationSettingsManager
211212
packages: ProjectPackageManager
213+
package_protection_rules: ProjectPackageProtectionRuleManager
212214
pagesdomains: ProjectPagesDomainManager
213215
pipelines: ProjectPipelineManager
214216
pipelineschedules: ProjectPipelineScheduleManager

tests/functional/api/test_packages.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66

77
from collections.abc import Iterator
88

9-
from gitlab.v4.objects import GenericPackage
9+
import pytest
10+
11+
from gitlab import Gitlab
12+
from gitlab.v4.objects import GenericPackage, Project, ProjectPackageProtectionRule
1013

1114
package_name = "hello-world"
1215
package_version = "v1.0.0"
@@ -15,6 +18,11 @@
1518
file_content = "package content"
1619

1720

21+
@pytest.fixture(scope="module", autouse=True)
22+
def protected_package_feature(gl: Gitlab):
23+
gl.features.set(name="packages_protected_packages", value=True)
24+
25+
1826
def test_list_project_packages(project):
1927
packages = project.packages.list()
2028
assert isinstance(packages, list)
@@ -148,3 +156,26 @@ def test_stream_generic_package_to_file(tmp_path, project):
148156

149157
with open(path, "r") as f:
150158
assert f.read() == file_content
159+
160+
161+
def test_list_project_protected_packages(project: Project):
162+
rules = project.package_protection_rules.list()
163+
assert isinstance(rules, list)
164+
165+
166+
@pytest.mark.skip(reason="Not released yet")
167+
def test_create_project_protected_packages(project: Project):
168+
protected_package = project.package_protection_rules.create(
169+
{
170+
"package_name_pattern": "v*",
171+
"package_type": "npm",
172+
"minimum_access_level_for_push": "maintainer",
173+
}
174+
)
175+
assert isinstance(protected_package, ProjectPackageProtectionRule)
176+
assert protected_package.package_type == "npm"
177+
178+
protected_package.minimum_access_level_for_push = "owner"
179+
protected_package.save()
180+
181+
protected_package.delete()
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""
2+
GitLab API: https://docs.gitlab.com/ee/api/project_packages_protection_rules.html
3+
"""
4+
5+
import pytest
6+
import responses
7+
8+
from gitlab.v4.objects import ProjectPackageProtectionRule
9+
10+
protected_package_content = {
11+
"id": 1,
12+
"project_id": 7,
13+
"package_name_pattern": "v*",
14+
"package_type": "npm",
15+
"minimum_access_level_for_push": "maintainer",
16+
}
17+
18+
19+
@pytest.fixture
20+
def resp_list_protected_packages():
21+
with responses.RequestsMock() as rsps:
22+
rsps.add(
23+
method=responses.GET,
24+
url="http://localhost/api/v4/projects/1/packages/protection/rules",
25+
json=[protected_package_content],
26+
content_type="application/json",
27+
status=200,
28+
)
29+
yield rsps
30+
31+
32+
@pytest.fixture
33+
def resp_create_protected_package():
34+
with responses.RequestsMock() as rsps:
35+
rsps.add(
36+
method=responses.POST,
37+
url="http://localhost/api/v4/projects/1/packages/protection/rules",
38+
json=protected_package_content,
39+
content_type="application/json",
40+
status=201,
41+
)
42+
yield rsps
43+
44+
45+
@pytest.fixture
46+
def resp_update_protected_package():
47+
updated_content = protected_package_content.copy()
48+
updated_content["package_name_pattern"] = "abc*"
49+
50+
with responses.RequestsMock() as rsps:
51+
rsps.add(
52+
method=responses.PATCH,
53+
url="http://localhost/api/v4/projects/1/packages/protection/rules/1",
54+
json=updated_content,
55+
content_type="application/json",
56+
status=200,
57+
)
58+
yield rsps
59+
60+
61+
@pytest.fixture
62+
def resp_delete_protected_package():
63+
with responses.RequestsMock() as rsps:
64+
rsps.add(
65+
method=responses.DELETE,
66+
url="http://localhost/api/v4/projects/1/packages/protection/rules/1",
67+
status=204,
68+
)
69+
yield rsps
70+
71+
72+
def test_list_project_protected_packages(project, resp_list_protected_packages):
73+
protected_package = project.package_protection_rules.list()[0]
74+
assert isinstance(protected_package, ProjectPackageProtectionRule)
75+
assert protected_package.package_type == "npm"
76+
77+
78+
def test_create_project_protected_package(project, resp_create_protected_package):
79+
protected_package = project.package_protection_rules.create(
80+
{
81+
"package_name_pattern": "v*",
82+
"package_type": "npm",
83+
"minimum_access_level_for_push": "maintainer",
84+
}
85+
)
86+
assert isinstance(protected_package, ProjectPackageProtectionRule)
87+
assert protected_package.package_type == "npm"
88+
89+
90+
def test_update_project_protected_package(project, resp_update_protected_package):
91+
updated = project.package_protection_rules.update(
92+
1, {"package_name_pattern": "abc*"}
93+
)
94+
assert updated["package_name_pattern"] == "abc*"
95+
96+
97+
def test_delete_project_protected_package(project, resp_delete_protected_package):
98+
project.package_protection_rules.delete(1)

0 commit comments

Comments
 (0)
0